<?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>netlify on Daan Geijs</title>
    <link>https://www.daangeijs.nl/tags/netlify/</link>
    <description>Recent content in netlify on Daan Geijs</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 22 Aug 2023 12:48:00 +0100</lastBuildDate><atom:link href="https://www.daangeijs.nl/tags/netlify/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Website Analytics with Umami, Netlify and a self-hosted database. </title>
      <link>https://www.daangeijs.nl/posts/umami-netlify/</link>
      <pubDate>Tue, 22 Aug 2023 12:48:00 +0100</pubDate>
      
      <guid>https://www.daangeijs.nl/posts/umami-netlify/</guid>
      <description>Umami is a sleek, open-source analytics tool that provides an alternative to mainstream solutions like Google Analytics. Its simplicity and transparency make it a preferred choice for those wary of the intricacies and potential privacy concerns associated with bigger platforms.</description>
      <content:encoded><![CDATA[<p><figure>
    <img loading="lazy" src="cover.jpg"/> 
</figure>

Umami is a sleek, open-source analytics tool that provides an alternative to mainstream solutions like Google Analytics. Its simplicity and transparency make it a preferred choice for those wary of the intricacies and potential privacy concerns associated with bigger platforms.</p>
<p>In this case I like having autonomy and control of hosting my own data, but I also appreciate the efficiency and scalability of cloud services. That&rsquo;s why, I&rsquo;ve opted to host the database needed for Umami at home on my homeserver using Proxmox.  However, when it comes to the dashboard – the visual heart of Umami – I use Netlify. Hosting the Umami dashboard on Netlify not only offloads my trusty NUC from running yet another service but also made installation a breeze with Netlify&rsquo;s effortless deployment process. In this article I will show you how I set it up.</p>
<h2 id="setting-up-database-on-proxmox">Setting Up Database on Proxmox</h2>
<ol>
<li>
<p><strong>Download CT Template</strong>: Begin by obtaining the <code>turnkey-postgresql</code> CT template. The easiest way to do this is to download the template from the Proxmox web interface. Navigate to &ldquo;Templates&rdquo; -&gt; &ldquo;Download&rdquo; and search for &ldquo;turnkey-postgresql&rdquo;. Select the template and click &ldquo;Download&rdquo;.</p>
</li>
<li>
<p><strong>Create a LXC container</strong>:
<figure>
    <img loading="lazy" src="1.png"/> 
</figure>
</p>
<ul>
<li>Assign a fixed IP address (fixed to enable port forwarding).</li>
<li>Allocate 1024MB memory and 1024MB swap.</li>
<li>Dedicate 1 CPU core.</li>
<li>Designate 16GB for disk storage.</li>
<li>Ensure &ldquo;start after created&rdquo; is selected.</li>
</ul>
</li>
</ol>
<p>For me these where the resources that I had available, but you can adjust these to your own needs.</p>
<ol start="3">
<li><strong>Complete Initialization</strong>: Access the console of your started container, log in with <code>root</code> and the password you set up at the previous step. Complete the installation, skipping any unnecessary add-ons but making sure to apply the updates.
<figure>
    <img loading="lazy" src="3.png"/> 
</figure>
</li>
<li><strong>Database Setup</strong>: Navigate to the browser using assigned-static-IP-address:12322 or simply input the IP address. This will take you to a dashboard where you can select Adminer. Use Adminer to log in with PostgreSQL credentials. Create a table named <code>umami</code>.
<figure>
    <img loading="lazy" src="5.png"/> 
</figure>
</li>
<li><strong>Port forwarding</strong> Make sure you don&rsquo;t forget to enable port forwarding (5432) to the IP address of your running Postgres container. Ofcourse, this completely depends on your network setup. Keep in mind that exposing a port does come with security vulnerabilities. If you have an Ubiquiti router <a href="/posts/ubiquiti-vlan/">you can read this article</a> for more information on how to set this up in a more safe way.</li>
</ol>
<h2 id="deploying-umami-on-netlify">Deploying Umami on Netlify</h2>
<ol>
<li>
<p><strong>Fork Repository</strong>: Fork the Umami repository to your GitHub account:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">https://github.com/umami-software/umami
</span></span></code></pre></div></li>
<li>
<p><strong>Netlify Setup</strong>:</p>
<ul>
<li>Log into Netlify.</li>
<li>Choose &ldquo;Add New Site&rdquo; -&gt; &ldquo;Import Existing Site&rdquo;.</li>
<li>Opt for &ldquo;Deploy with GitHub&rdquo;.</li>
<li>Select your forked Umami repository.</li>
</ul>
</li>
<li>
<p><strong>Environment Variable</strong>:
<figure>
    <img loading="lazy" src="6.png"/> 
</figure>
</p>
<ul>
<li>In the site settings of your new project, navigate to &ldquo;Site configuration&rdquo; -&gt; &ldquo;Environment variables&rdquo;.</li>
<li>Add the <code>DATABASE_URL</code> variable with the value:
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">postgresql://<span class="p">&lt;</span><span class="nt">postgres_account</span><span class="p">&gt;</span>:<span class="p">&lt;</span><span class="nt">postgress_password</span><span class="p">&gt;</span>@<span class="p">&lt;</span><span class="nt">your_db_ip</span><span class="p">&gt;</span>/umami
</span></span></code></pre></div></li>
</ul>
</li>
<li>
<p><strong>Trigger Deployment</strong>:
<figure>
    <img loading="lazy" src="7.png"/> 
</figure>
</p>
<ul>
<li>In the Netlify dashboard, go to &ldquo;Deploys&rdquo;.</li>
<li>Select &ldquo;Trigger Deploy&rdquo; and choose &ldquo;Clear cache and deploy site&rdquo;.</li>
</ul>
</li>
</ol>
<p>The example here is just with Proxmox, but you can choose any popular solutions like AWS, Azure, DigitalOcean, or Heroku— provided they support PostgreSQL.  At the end you just need to update the URL in the Netlify dashboard.  Choose what&rsquo;s best for your needs.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Journey to Optimized Images: Hugo, Decap CMS, and Page Bundles</title>
      <link>https://www.daangeijs.nl/posts/hugo-papermodx-optimize/</link>
      <pubDate>Wed, 09 Aug 2023 21:48:00 +0100</pubDate>
      
      <guid>https://www.daangeijs.nl/posts/hugo-papermodx-optimize/</guid>
      <description>This turned out to be an unexpected long journey. It all began when I realized that my &lt;a href=&#34;https://dekeukenvandael.nl&#34;&gt;website&lt;/a&gt; images weren&amp;rsquo;t optimized as I had expected. I had been relying on the PaperMod and PaperModX themes in Hugo to handle image optimization. Everything seemed to be in place, but my images were still bulky and slow to load. The problem was evident, but the cause? Not so much.</description>
      <content:encoded><![CDATA[<p>This turned out to be an unexpected long journey. It all began when I realized that my <a href="https://dekeukenvandael.nl">website</a> images weren&rsquo;t optimized as I had expected. I had been relying on the PaperMod and PaperModX themes in Hugo to handle image optimization. Everything seemed to be in place, but my images were still bulky and slow to load. The problem was evident, but the cause? Not so much.</p>
<p>Digging into the problem, I started by examining the <code>cover.html</code> file in the theme. This file is crucial for handling images. As I skimmed through the lines, an interesting section of the code caught my attention:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="err">##</span> <span class="nx">themes</span><span class="o">/</span><span class="nx">PaperMod</span><span class="o">/</span><span class="nx">layouts</span><span class="o">/</span><span class="nx">partials</span><span class="o">/</span><span class="nx">cover</span><span class="p">.</span><span class="nx">html</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">{{</span><span class="o">-</span> <span class="k">if</span> <span class="err">$</span><span class="nx">cover</span> <span class="o">-</span><span class="p">}}{{</span><span class="cm">/* i.e it is present in page bundle */</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span><span class="p">.</span><span class="nx">optimisation</span> <span class="nx">code</span> <span class="nx">here</span>
</span></span><span class="line"><span class="cl"><span class="p">{{</span><span class="o">-</span> <span class="k">else</span> <span class="p">}}{{</span><span class="cm">/* For absolute urls and external links, no img processing here */</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span><span class="p">.</span> <span class="nx">well</span><span class="o">...</span><span class="nx">do</span> <span class="nx">nothing</span>
</span></span></code></pre></div><p>The theme was checking for images within something called a &ldquo;page bundle.&rdquo; If the image wasn&rsquo;t within this bundle, optimization processes wouldn&rsquo;t be triggered. That was my &ldquo;Aha!&rdquo; moment. For the themes to work their magic, my content needed to be organized into Hugo&rsquo;s page bundles.</p>
<p>So, with newfound clarity, I set about restructuring my content into these page bundles. The results? When building Hugo locally, the images were automatically resized and optimized, all thanks to the wonders of my new page bundles!</p>
<p>When I transitioned to page bundles, I anticipated that my <code>config.yml</code> for the CMS would require some adjustments. Luckily the CMS supported Page bundles by using so called <code>collections</code> and I followed the <a href="https://decapcms.org/docs/collection-types/">official documentation</a> making the adjustments needed.</p>
<p>However, with every solution came a new challenge. Now that my content was structured the right way for image optimization, my newly configured Decap CMS (previously Netlify CMS) threw a tantrum. Suddenly, it stopped listing any of my articles.  This was the most timeconsuming and puzzling setback.</p>
<p>I scoured the internet for answers, hoping to stumble upon someone who had faced a similar issue. And then, I came across a post on <a href="https://blog.millerti.me/2021/12/23/supporting-hugo-page-bundles-in-netlify-cms/">millerti.me</a> that held the missing piece to my puzzle. The article mentioned the specific lines I needed to integrate in the collections:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># Support Hugo page bundles that puts index.md and images in folders named by slug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;{{slug}}/index&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">media_folder</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;&#34;</span><span class="w">
</span></span></span></code></pre></div><p>Adding these lines was the magic touch. Now my CMS seamlessly stored new content, and it also listed my previous articles again and everything worked smoothly. This all resulted in the following config.yml:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c">## admin/config.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">backend</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">git-gateway</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">branch</span><span class="p">:</span><span class="w"> </span><span class="l">main</span><span class="w"> </span><span class="c"># Branch to update (optional; defaults to master)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">site_url</span><span class="p">:</span><span class="w"> </span><span class="l">https://dekeukenvandael.nl</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">logo_url</span><span class="p">:</span><span class="w"> </span><span class="l">https://www.dekeukenvandael.nl/images/static/logo.svg</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">publish_mode</span><span class="p">:</span><span class="w"> </span><span class="l">editorial_workflow</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">media_folder</span><span class="p">:</span><span class="w"> </span><span class="l">static/images</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">public_folder</span><span class="p">:</span><span class="w"> </span><span class="l">/images</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">collections</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;recipes&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">label</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Recipes&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">label_singular</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Recipe&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">folder</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;content/recipes&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">create</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># Support Hugo page bundles that puts index.md and images in folders named by slug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;{{year}}-{{month}}-{{day}}-{{slug}}/index&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c"># Note the usage of title here instead of slug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">preview_path</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;recipes/{{year}}-{{month}}-{{day}}-{{title}}&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">preview_path_date_field</span><span class="p">:</span><span class="w"> </span><span class="l">date</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">filter</span><span class="p">:</span><span class="w"> </span>{<span class="nt">field</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;ignore&#34;</span><span class="nt">, value</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">editor</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">preview</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">fields</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Title&#39;, name: &#39;title&#39;, widget</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;string&#39;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Publish Date&#39;, name: &#39;date&#39;, widget</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;datetime&#39;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Authors&#34;</span><span class="nt">, name</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;author&#34;</span><span class="nt">, widget</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;list&#34;</span><span class="nt">, summary</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;{{fields.author_name}}&#34;</span><span class="nt">, field</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">label</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Author name&#34;</span><span class="nt">, name</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;author_name&#34;</span><span class="nt">, widget</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;string&#34;</span><span class="w"> </span>}}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Tags&#39;, name: &#39;tags&#39;, widget: &#39;list&#39;, required: false, items</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>{<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;string&#39;</span><span class="w"> </span>}<span class="p">]</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Categories&#39;, name: &#39;categories&#39;, widget: &#39;list&#39;, required: false, items</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>{<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;string&#39;</span><span class="w"> </span>}<span class="p">]</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Cover Image&#39;, name: &#39;cover&#39;, widget: &#39;object&#39;, fields</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>{<span class="w"> </span><span class="nt">label: &#39;Image&#39;, name: &#39;image&#39;, required: false, widget</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;image&#39;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Summary&#39;, name: &#39;summary&#39;, widget: &#39;text&#39;, required</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- {<span class="w"> </span><span class="nt">label: &#39;Body&#39;, name: &#39;body&#39;, widget</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;markdown&#39;</span><span class="w"> </span>}<span class="w">
</span></span></span></code></pre></div><p>I hope it helps to reduce the time and effort for others facing similar issues. It wasn&rsquo;t a straightforward process for me, and I&rsquo;d be pleased if others can benefit from the lessons I learned. Maybe with the time you saved you can write an nice article about how this helped you ;).</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
