<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Nginx on Carlos Vaz</title>
    <link>https://carlosvaz.com/tags/nginx/</link>
    <description>Recent content in Nginx on Carlos Vaz</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <managingEditor>carlos@carjorvaz.com (Carlos Vaz)</managingEditor>
    <webMaster>carlos@carjorvaz.com (Carlos Vaz)</webMaster>
    <lastBuildDate>Sat, 05 Aug 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://carlosvaz.com/tags/nginx/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The Holy Grail Nextcloud setup made easy by NixOS</title>
      <link>https://carlosvaz.com/posts/the-holy-grail-nextcloud-setup-made-easy-by-nixos/</link>
      <pubDate>Sat, 05 Aug 2023 00:00:00 +0000</pubDate><author>carlos@carjorvaz.com (Carlos Vaz)</author>
      <guid>https://carlosvaz.com/posts/the-holy-grail-nextcloud-setup-made-easy-by-nixos/</guid>
      <description>&lt;p&gt;Nextcloud really is the central piece to most people&amp;rsquo;s self-hosted infrastructure.&lt;/p&gt;&#xA;&lt;p&gt;Providing file synchronization, a web interface to navigate through them, calendar, contacts, tasks, kanban and webmail, it presents itself as a complete GSuite self-hosted alternative.&lt;/p&gt;&#xA;&lt;p&gt;Hosting Nextcloud has become easier over time, thanks to its docker-compose example setups and to the Snap for use mostly on Ubuntu systems. However, having a faster and more optimized setup can take some effort on these platforms. Thankfully, on NixOS it&amp;rsquo;s not hard at all, as I&amp;rsquo;ll show you.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Nextcloud really is the central piece to most people&rsquo;s self-hosted infrastructure.</p>
<p>Providing file synchronization, a web interface to navigate through them, calendar, contacts, tasks, kanban and webmail, it presents itself as a complete GSuite self-hosted alternative.</p>
<p>Hosting Nextcloud has become easier over time, thanks to its docker-compose example setups and to the Snap for use mostly on Ubuntu systems. However, having a faster and more optimized setup can take some effort on these platforms. Thankfully, on NixOS it&rsquo;s not hard at all, as I&rsquo;ll show you.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nix" data-lang="nix"><span style="display:flex;"><span>{ self<span style="color:#f92672">,</span> config<span style="color:#f92672">,</span> lib<span style="color:#f92672">,</span> pkgs<span style="color:#f92672">,</span> <span style="color:#f92672">...</span> }:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  services <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    nginx<span style="color:#f92672">.</span>virtualHosts <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#34;cloud.example.com&#34;</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>        forceSSL <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>        enableACME <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#34;onlyoffice.example.com&#34;</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>        forceSSL <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>        enableACME <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    nextcloud <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      hostName <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;cloud.example.com&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       <span style="color:#75715e"># Need to manually increment with every major upgrade.</span>
</span></span><span style="display:flex;"><span>      package <span style="color:#f92672">=</span> pkgs<span style="color:#f92672">.</span>nextcloud27;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Let NixOS install and configure the database automatically.</span>
</span></span><span style="display:flex;"><span>      database<span style="color:#f92672">.</span>createLocally <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Let NixOS install and configure Redis caching automatically.</span>
</span></span><span style="display:flex;"><span>      configureRedis <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Increase the maximum file upload size to avoid problems uploading videos.</span>
</span></span><span style="display:flex;"><span>      maxUploadSize <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;16G&#34;</span>;
</span></span><span style="display:flex;"><span>      https <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      enableBrokenCiphersForSSE <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      autoUpdateApps<span style="color:#f92672">.</span>enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      extraAppsEnable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      extraApps <span style="color:#f92672">=</span> <span style="color:#66d9ef">with</span> config<span style="color:#f92672">.</span>services<span style="color:#f92672">.</span>nextcloud<span style="color:#f92672">.</span>package<span style="color:#f92672">.</span>packages<span style="color:#f92672">.</span>apps; {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># List of apps we want to install and are already packaged in</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/nextcloud/packages/nextcloud-apps.json</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">inherit</span> calendar contacts mail notes onlyoffice tasks;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># Custom app installation example.</span>
</span></span><span style="display:flex;"><span>        cookbook <span style="color:#f92672">=</span> pkgs<span style="color:#f92672">.</span>fetchNextcloudApp <span style="color:#66d9ef">rec</span> {
</span></span><span style="display:flex;"><span>          url <span style="color:#f92672">=</span>
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;https://github.com/nextcloud/cookbook/releases/download/v0.10.2/Cookbook-0.10.2.tar.gz&#34;</span>;
</span></span><span style="display:flex;"><span>          sha256 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;sha256-XgBwUr26qW6wvqhrnhhhhcN4wkI+eXDHnNSm1HDbP6M=&#34;</span>;
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      config <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>        overwriteProtocol <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https&#34;</span>;
</span></span><span style="display:flex;"><span>        defaultPhoneRegion <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;PT&#34;</span>;
</span></span><span style="display:flex;"><span>        dbtype <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;pgsql&#34;</span>;
</span></span><span style="display:flex;"><span>        adminuser <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;admin&#34;</span>;
</span></span><span style="display:flex;"><span>        adminpassFile <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;/path/to/nextcloud-admin-pass&#34;</span>;
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    onlyoffice <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      hostname <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;onlyoffice.example.com&#34;</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>  };
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><p>You may want to proceed with caution while setting up the OnlyOffice server, which will allow for Google Docs-like functionality on our Nextcloud instance, by having it only accessible inside your VPN or by setting the <code>services.onlyoffice.jwtSecretFile</code> option if exposed to the public Internet.</p>
<p>With this snippet, a Nextcloud instance with a selection of pre-installed Apps, PostgreSQL as a database, Redis Caching and Let&rsquo;s Encrypt certificates will be set up for you.</p>
<p>To connect to the OnlyOffice server, configure it appropriately in Administration settings &gt; ONLYOFFICE &gt; ONLYOFFICE Docs address.</p>
<h2 id="backups">Backups</h2>
<p>In this configuration, we need to persist the <code>/var/lib/nextcloud</code> and <code>/var/lib/postgresql</code> directories.</p>
<p>For backing up, you could copy  <code>/var/lib/nextcloud</code> to another computer and, for the database, dump it to a file and copy it to another computer as well, as described <a href="https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html">in the official Nextcloud documentation</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Once again, NixOS proves itself as an amazing self-hosting platform.</p>
<p>Nextcloud, in its default configuration, is sometimes known for running slow.
Thanks to NixOS, we&rsquo;ve optimized its performance and that&rsquo;s quite impactful, as it&rsquo;s my most used self-hosted application.
Having all of these apps running on Nextcloud has enabled me to move on from GSuite to a mostly autonomous and self-hosted infrastructure.</p>
<p>In the future, I look forward to being able to use Collabora/Nextcloud Office instead of OnlyOffice, as it&rsquo;s more aligned with Nextcloud&rsquo;s philosophical goals and hasn&rsquo;t done <a href="https://help.nextcloud.com/t/onlyoffice-removed-web-mobile-editing-from-version-5-5-0-of-community-document-server/74360">suspicious decisions in the past</a>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://nixos.wiki/wiki/Nextcloud">https://nixos.wiki/wiki/Nextcloud</a></li>
<li><a href="https://nixos.wiki/wiki/Onlyoffice-Documentserver">https://nixos.wiki/wiki/Onlyoffice-Documentserver</a></li>
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html">https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html</a></li>
<li><a href="https://docs.nextcloud.com/server/latest/admin_manual/maintenance/restore.html">https://docs.nextcloud.com/server/latest/admin_manual/maintenance/restore.html</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Setting up a WordPress website on NixOS</title>
      <link>https://carlosvaz.com/posts/setting-up-a-wordpress-website-on-nixos/</link>
      <pubDate>Tue, 01 Aug 2023 00:00:00 +0000</pubDate><author>carlos@carjorvaz.com (Carlos Vaz)</author>
      <guid>https://carlosvaz.com/posts/setting-up-a-wordpress-website-on-nixos/</guid>
      <description>&lt;p&gt;Another instance where NixOS makes it easy to self-host services, this time we&amp;rsquo;re setting up WordPress using the upstream nixpkgs module and some auxiliary functions to help us package themes and plugins.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; lib&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  domain &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;example.com&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Auxiliary functions&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fetchPackage &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { name&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; version&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; hash&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; isTheme }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stdenv&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;mkDerivation &lt;span style=&#34;color:#66d9ef&#34;&gt;rec&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; name version hash;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      src &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; isTheme &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;theme&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plugin&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fetchzip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; name version hash;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://downloads.wordpress.org/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;type&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;version&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.zip&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      installPhase &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mkdir -p $out; cp -R * $out/&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fetchPlugin &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { name&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; version&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; hash }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (fetchPackage {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; name;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; version;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      hash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; hash;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      isTheme &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fetchTheme &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { name&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; version&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; hash }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (fetchPackage {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; name;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; version;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      hash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; hash;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      isTheme &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Plugins&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  google-site-kit &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (fetchPlugin {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;google-site-kit&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.103.0&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sha256-8QZ4XTCKVdIVtbTV7Ka4HVMiUGkBYkxsw8ctWDV8gxs=&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Themes&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  astra &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (fetchTheme {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;astra&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4.1.5&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sha256-X3Jv2kn0FCCOPgrID0ZU8CuSjm/Ia/d+om/ShP5IBgA=&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  services &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nginx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;virtualHosts&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;domain&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      enableACME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      forceSSL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    wordpress &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      webserver &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      sites&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;domain&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        plugins &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; google-site-kit; };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        themes &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; astra; };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        settings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { WP_DEFAULT_THEME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;astra&amp;#34;&lt;/span&gt;; };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# As this is a root on tmpfs system, we use the impermanence&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# NixOS module to persist WordPress state between reboots.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# You can omit the next two lines if using a regular configuration.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  environment&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;persistence&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/persist&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;directories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/var/lib/mysql&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/var/lib/wordpress&amp;#34;&lt;/span&gt; ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I configure WordPress to use Nginx as the web server instead of httpd as it&amp;rsquo;s what I already use as a reverse proxy for my other self-hosted applications.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Another instance where NixOS makes it easy to self-host services, this time we&rsquo;re setting up WordPress using the upstream nixpkgs module and some auxiliary functions to help us package themes and plugins.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nix" data-lang="nix"><span style="display:flex;"><span>{ config<span style="color:#f92672">,</span> lib<span style="color:#f92672">,</span> pkgs<span style="color:#f92672">,</span> <span style="color:#f92672">...</span> }:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span>
</span></span><span style="display:flex;"><span>  domain <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;example.com&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># Auxiliary functions</span>
</span></span><span style="display:flex;"><span>  fetchPackage <span style="color:#f92672">=</span> { name<span style="color:#f92672">,</span> version<span style="color:#f92672">,</span> hash<span style="color:#f92672">,</span> isTheme }:
</span></span><span style="display:flex;"><span>    pkgs<span style="color:#f92672">.</span>stdenv<span style="color:#f92672">.</span>mkDerivation <span style="color:#66d9ef">rec</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">inherit</span> name version hash;
</span></span><span style="display:flex;"><span>      src <span style="color:#f92672">=</span> <span style="color:#66d9ef">let</span> type <span style="color:#f92672">=</span> <span style="color:#66d9ef">if</span> isTheme <span style="color:#66d9ef">then</span> <span style="color:#e6db74">&#34;theme&#34;</span> <span style="color:#66d9ef">else</span> <span style="color:#e6db74">&#34;plugin&#34;</span>;
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">in</span> pkgs<span style="color:#f92672">.</span>fetchzip {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">inherit</span> name version hash;
</span></span><span style="display:flex;"><span>        url <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://downloads.wordpress.org/</span><span style="color:#e6db74">${</span>type<span style="color:#e6db74">}</span><span style="color:#e6db74">/</span><span style="color:#e6db74">${</span>name<span style="color:#e6db74">}</span><span style="color:#e6db74">.</span><span style="color:#e6db74">${</span>version<span style="color:#e6db74">}</span><span style="color:#e6db74">.zip&#34;</span>;
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>      installPhase <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;mkdir -p $out; cp -R * $out/&#34;</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  fetchPlugin <span style="color:#f92672">=</span> { name<span style="color:#f92672">,</span> version<span style="color:#f92672">,</span> hash }:
</span></span><span style="display:flex;"><span>    (fetchPackage {
</span></span><span style="display:flex;"><span>      name <span style="color:#f92672">=</span> name;
</span></span><span style="display:flex;"><span>      version <span style="color:#f92672">=</span> version;
</span></span><span style="display:flex;"><span>      hash <span style="color:#f92672">=</span> hash;
</span></span><span style="display:flex;"><span>      isTheme <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  fetchTheme <span style="color:#f92672">=</span> { name<span style="color:#f92672">,</span> version<span style="color:#f92672">,</span> hash }:
</span></span><span style="display:flex;"><span>    (fetchPackage {
</span></span><span style="display:flex;"><span>      name <span style="color:#f92672">=</span> name;
</span></span><span style="display:flex;"><span>      version <span style="color:#f92672">=</span> version;
</span></span><span style="display:flex;"><span>      hash <span style="color:#f92672">=</span> hash;
</span></span><span style="display:flex;"><span>      isTheme <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># Plugins</span>
</span></span><span style="display:flex;"><span>  google-site-kit <span style="color:#f92672">=</span> (fetchPlugin {
</span></span><span style="display:flex;"><span>    name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;google-site-kit&#34;</span>;
</span></span><span style="display:flex;"><span>    version <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;1.103.0&#34;</span>;
</span></span><span style="display:flex;"><span>    hash <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;sha256-8QZ4XTCKVdIVtbTV7Ka4HVMiUGkBYkxsw8ctWDV8gxs=&#34;</span>;
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># Themes</span>
</span></span><span style="display:flex;"><span>  astra <span style="color:#f92672">=</span> (fetchTheme {
</span></span><span style="display:flex;"><span>    name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;astra&#34;</span>;
</span></span><span style="display:flex;"><span>    version <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;4.1.5&#34;</span>;
</span></span><span style="display:flex;"><span>    hash <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;sha256-X3Jv2kn0FCCOPgrID0ZU8CuSjm/Ia/d+om/ShP5IBgA=&#34;</span>;
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> {
</span></span><span style="display:flex;"><span>  services <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    nginx<span style="color:#f92672">.</span>virtualHosts<span style="color:#f92672">.</span><span style="color:#e6db74">${</span>domain<span style="color:#e6db74">}</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      enableACME <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      forceSSL <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    wordpress <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      webserver <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nginx&#34;</span>;
</span></span><span style="display:flex;"><span>      sites<span style="color:#f92672">.</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>domain<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>        plugins <span style="color:#f92672">=</span> { <span style="color:#66d9ef">inherit</span> google-site-kit; };
</span></span><span style="display:flex;"><span>        themes <span style="color:#f92672">=</span> { <span style="color:#66d9ef">inherit</span> astra; };
</span></span><span style="display:flex;"><span>        settings <span style="color:#f92672">=</span> { WP_DEFAULT_THEME <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;astra&#34;</span>; };
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>  };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># As this is a root on tmpfs system, we use the impermanence</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># NixOS module to persist WordPress state between reboots.</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># You can omit the next two lines if using a regular configuration.</span>
</span></span><span style="display:flex;"><span>  environment<span style="color:#f92672">.</span>persistence<span style="color:#f92672">.</span><span style="color:#e6db74">&#34;/persist&#34;</span><span style="color:#f92672">.</span>directories <span style="color:#f92672">=</span>
</span></span><span style="display:flex;"><span>    [ <span style="color:#e6db74">&#34;/var/lib/mysql&#34;</span> <span style="color:#e6db74">&#34;/var/lib/wordpress&#34;</span> ];
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><p>I configure WordPress to use Nginx as the web server instead of httpd as it&rsquo;s what I already use as a reverse proxy for my other self-hosted applications.</p>
<p>After deploying this configuration, you&rsquo;ll be met with the famous 5-minute WordPress installation at your domain, with a MySQL database and Let&rsquo;s Encrypt automatically configured for you.
For demonstration, the Astra theme and the Google Site Kit plugin will also be automatically installed.</p>
<p>You&rsquo;re then presented with the usual WordPress dashboard, where you&rsquo;re free to enable the plugins we just installed and also do other miscellaneous configuration.
In theory, these steps can also be declarative using the <code>services.wordpress.sites.&lt;domain&gt;.extraConfig</code>, although I had trouble doing that and was met with database connection errors when rebuilding the configuration.</p>
<p>Beyond the ease of installation, there may be advantages to using WordPress on NixOS instead of a docker-compose setup, for example.
WordPress is known to quickly become a remote shell for intruders if not properly looked after and regularly updated.
On NixOS, the only themes and plugins the WordPress instance will have access to will be the ones we explicitly set in the NixOS module, preventing the installation of plugins with malware by some distracted administrator through the Web interface.
Thanks to the Nix store&rsquo;s properties of immutability and restricted permissions, it&rsquo;ll also be harder for malicious plugins to modify themselves when compared to normal setups.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Once again, NixOS made setting up another self-hosted service very easy.</p>
<p>This post will help you set up a basic WordPress instance, you&rsquo;re then free to install more plugins and to optimize the website further.
There are some suggestions on the relevant <a href="https://nixos.wiki/wiki/Wordpress#Tips_and_tricks">NixOS Wiki page</a>.</p>
<p>Although I felt I learned something with this experience, I still prefer using simple Static Site Generators like <a href="https://gohugo.io">Hugo</a> for my personal projects.
Using Hugo along with <a href="https://ox-hugo.scripter.co">ox-hugo</a> allows me to have a website that&rsquo;s quite &ldquo;declarative&rdquo;, configured with plain text files, where I can do easy version control and deploy anywhere, many times for free.
It also produces very fast sites without much effort, many times being close to a perfect score on the <a href="https://developer.chrome.com/docs/lighthouse/overview/">Lighthouse speed test</a>. I also can be more relieved about security and maintenance as it&rsquo;s just my webserver serving static files, without any backend or database to be exploited.</p>
<p>Nonetheless, about one third of the Web are WordPress websites and it&rsquo;s useful to know how to set them up and configure them on NixOS.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://nixos.wiki/wiki/Wordpress">https://nixos.wiki/wiki/Wordpress</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Setting up wildcard Let&#39;s Encrypt certificates on NixOS</title>
      <link>https://carlosvaz.com/posts/setting-up-wildcard-lets-encrypt-certificates-on-nixos/</link>
      <pubDate>Mon, 26 Dec 2022 00:00:00 +0000</pubDate><author>carlos@carjorvaz.com (Carlos Vaz)</author>
      <guid>https://carlosvaz.com/posts/setting-up-wildcard-lets-encrypt-certificates-on-nixos/</guid>
      <description>&lt;p&gt;After setting up an Headscale server in order to have a mesh-VPN for my devices, I was now able to set up self-hosted services on my home server and access them anywhere in the world.&lt;/p&gt;&#xA;&lt;p&gt;However, because they&amp;rsquo;re inside this private network, I&amp;rsquo;m not able to get Let&amp;rsquo;s Encrypt certificates through the usual HTTP-01 challenge, exactly because the home server is not accessible from the public Internet.&lt;/p&gt;&#xA;&lt;p&gt;Because of this, and to prevent my browsers from screaming that I&amp;rsquo;m acessing my services through an &amp;ldquo;Insecure Connection&amp;rdquo; (even though the encrypted connection provided by Tailscale is plenty secure), I decided to set up wildcard certificates, provided by Let&amp;rsquo;s Encrypt.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>After setting up an Headscale server in order to have a mesh-VPN for my devices, I was now able to set up self-hosted services on my home server and access them anywhere in the world.</p>
<p>However, because they&rsquo;re inside this private network, I&rsquo;m not able to get Let&rsquo;s Encrypt certificates through the usual HTTP-01 challenge, exactly because the home server is not accessible from the public Internet.</p>
<p>Because of this, and to prevent my browsers from screaming that I&rsquo;m acessing my services through an &ldquo;Insecure Connection&rdquo; (even though the encrypted connection provided by Tailscale is plenty secure), I decided to set up wildcard certificates, provided by Let&rsquo;s Encrypt.</p>
<h2 id="nixos-configuration">NixOS configuration</h2>
<p>As usual, the NixOS configuration part of this setup is not too difficult:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nix" data-lang="nix"><span style="display:flex;"><span>{ self<span style="color:#f92672">,</span> config<span style="color:#f92672">,</span> lib<span style="color:#f92672">,</span> pkgs<span style="color:#f92672">,</span> <span style="color:#f92672">...</span> }:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  security<span style="color:#f92672">.</span>acme <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    acceptTerms <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>    defaults<span style="color:#f92672">.</span>email <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;john.doe@example.com&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    certs<span style="color:#f92672">.</span><span style="color:#e6db74">&#34;example.com&#34;</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      domain <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;example.com&#34;</span>;
</span></span><span style="display:flex;"><span>      extraDomainNames <span style="color:#f92672">=</span> [ <span style="color:#e6db74">&#34;*.example.com&#34;</span> ];
</span></span><span style="display:flex;"><span>      dnsProvider <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;ovh&#34;</span>;
</span></span><span style="display:flex;"><span>      dnsPropagationCheck <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>      credentialsFile <span style="color:#f92672">=</span> <span style="color:#e6db74">/path/to/secrets/file</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>  };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  users<span style="color:#f92672">.</span>users<span style="color:#f92672">.</span>nginx<span style="color:#f92672">.</span>extraGroups <span style="color:#f92672">=</span> [ <span style="color:#e6db74">&#34;acme&#34;</span> ];
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><p>In this example, I set my provider to OVH. You may want to change this to <a href="https://go-acme.github.io/lego/dns/">your provider of choice</a>.</p>
<p>Also worthy of note is that we need to add the <code>nginx</code> user to the <code>acme</code> group, so that nginx can read the certificate files created by the acme service.
Adjust this according to your preference of reverse proxy software.</p>
<h2 id="ovh-api-credentials">OVH API credentials</h2>
<p>The DNS-01 challenge, as the name implies, requires setting up DNS records to prove ownership of resources.
Because of that, we&rsquo;ll need to set up an API key for the acme NixOS module, so that it can set up these records automatically.</p>
<p>To create these credentials:</p>
<ol>
<li>Go to <a href="https://eu.api.ovh.com/createToken/">https://eu.api.ovh.com/createToken/</a></li>
<li>Fill the form with the required information as shown below:
<ul>
<li>Account ID or email address: usual OVH login</li>
<li>Password: usual OVH password</li>
<li>Script Name: for example, &ldquo;NixOS wildcard certificate&rdquo;</li>
<li>Script description: for example, &ldquo;NixOS wildcard certificate&rdquo;</li>
<li>Validity: Unlimited</li>
<li>Rights: use the + button to add the following lines
<ul>
<li><code>POST</code> : <code>/domain/zone/*</code></li>
<li><code>DELETE</code> : <code>/domain/zone/*</code></li>
</ul>
</li>
</ul>
</li>
</ol>
<p>After creating them, we&rsquo;ll need to place them in the <code>/path/to/secrets/file</code>.</p>
<p>Be careful not to share these publicly.
I personally use <a href="https://github.com/ryantm/agenix">agenix</a> for managing secrets in my NixOS configuration.</p>
<p>As per the <a href="https://go-acme.github.io/lego/dns/ovh/">OVH lego provider documentation</a>, this file will include something like this:</p>





<pre tabindex="0"><code class="language-nil" data-lang="nil">OVH_ENDPOINT=ovh-eu
OVH_APPLICATION_KEY=&lt;application-key&gt;
OVH_APPLICATION_SECRET=&lt;application-secret&gt;
OVH_CONSUMER_KEY=&lt;consumer-key&gt;</code></pre><h2 id="dns-zone-configuration">DNS zone configuration</h2>
<p>Initially, I tried to set up DNS like this:</p>
<ul>
<li>Create a wildcard CNAME record so that <code>*.example.com</code> points to <code>home-server.tailnet.example.com</code>.</li>
</ul>
<p>However, with this setup, the acme service failed to fetch the certificate.</p>
<p>I ended up setting DNS this way instead:</p>
<ul>
<li>Create a wildcard A record so that <code>*.example.com</code> points to <code>100.64.0.1</code>, my home-server&rsquo;s Tailscale IP.</li>
</ul>
<p>Now everything worked perfectly, although I feel that the CNAME method was more elegant, as it didn&rsquo;t depend on the IP Tailscale assigned to my machine but only on its hostname and headscale&rsquo;s <a href="https://tailscale.com/kb/1081/magicdns/">MagicDNS</a>.</p>
<h2 id="using-the-certificate">Using the certificate</h2>
<p>Now, after running <code>nixos-rebuild switch</code> and making sure that no errors showed up while getting the certificate, all that&rsquo;s left is to start using it.</p>
<p>A simple nginx configuration that uses this certificate would like the following:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nix" data-lang="nix"><span style="display:flex;"><span>{ config<span style="color:#f92672">,</span> lib<span style="color:#f92672">,</span> pkgs<span style="color:#f92672">,</span> <span style="color:#f92672">...</span> }:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  services<span style="color:#f92672">.</span>nginx <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    virtualHosts <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#34;some-service.example.com&#34;</span> <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>        forceSSL <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
</span></span><span style="display:flex;"><span>        useACMEHost <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;example.com&#34;</span>;
</span></span><span style="display:flex;"><span>        locations<span style="color:#f92672">.</span><span style="color:#e6db74">&#34;/&#34;</span><span style="color:#f92672">.</span>proxyPass <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;http://127.0.0.1:12345&#34;</span>;
</span></span><span style="display:flex;"><span>      };
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>  };
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h2 id="closing-remarks">Closing remarks</h2>
<p>Once again, NixOS made this process really straightforward.</p>
<p>I have read that Caddy makes this workflow really easy as well, if I weren&rsquo;t using NixOS I&rsquo;d probably be using that instead.</p>
<p>This setup is now ready to provide self-hosted services only accessible inside the headscale mesh-VPN and without the headache of using self-signed certificates or skipping the &ldquo;Insecure Connection&rdquo; warnings all the time.
It also didn&rsquo;t require port-forwarding on my router and having my services available to the hostile and chaotic public Internet.</p>
<p>Another subtle consequence of using wildcard certificates is that there&rsquo;s improved privacy in what concerns <a href="https://en.wikipedia.org/wiki/Certificate_Transparency">certificate transparency</a>.
When someone searches for your domain at a service such as <a href="https://crt.sh/">crt.sh</a>, all they&rsquo;ll see is that a wildcard certificate was emitted for that domain.
This way, you&rsquo;ll avoid having a public list of all the private services you&rsquo;ve set up at home.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://nixos.org/manual/nixos/stable/index.html#module-security-acme-config-dns">https://nixos.org/manual/nixos/stable/index.html#module-security-acme-config-dns</a></li>
<li><a href="https://discourse.nixos.org/t/setup-a-wildcard-certificate-with-acme-on-a-custom-domain-name-hosted-by-powerdns/15055">https://discourse.nixos.org/t/setup-a-wildcard-certificate-with-acme-on-a-custom-domain-name-hosted-by-powerdns/15055</a></li>
<li><a href="https://go-acme.github.io/lego/dns/ovh/">https://go-acme.github.io/lego/dns/ovh/</a></li>
<li><a href="https://yunohost.org/en/providers/registrar/ovh/autodns">https://yunohost.org/en/providers/registrar/ovh/autodns</a></li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
