<?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Andrei Telteu</title><link>https://telteu.ro/</link><description>Recent content on Andrei Telteu</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>Andrei Telteu 2024</copyright><lastBuildDate>Sat, 25 Jan 2025 20:04:00 +0200</lastBuildDate><atom:link href="https://telteu.ro/index.xml" rel="self" type="application/rss+xml"/><item><title>How to configure Headscale and Traefik to proxy any service</title><link>https://telteu.ro/posts/headscale-with-traefik/</link><pubDate>Sat, 25 Jan 2025 20:04:00 +0200</pubDate><guid>https://telteu.ro/posts/headscale-with-traefik/</guid><description>Andrei Telteu https://telteu.ro/posts/headscale-with-traefik/ -&lt;h2 id="requirements">Requirements:&lt;/h2>
&lt;ul>
&lt;li>a linux server with a public IPv4 address&lt;/li>
&lt;li>docker and docker compose installed&lt;/li>
&lt;li>a domain/subdomain with a A DNS record pointing to your IP&lt;/li>
&lt;/ul>
&lt;p>I will use &lt;strong>example.com&lt;/strong> as the domain name in this example, please replace it with your domain/subdomain.&lt;/p>
&lt;h2 id="traefik">Traefik&lt;/h2>
&lt;p>Ssh to your public server where you want to host your vpn, make a folder called &lt;code>traefik&lt;/code> with the following files:
&lt;code>mkdir traefik &amp;amp;&amp;amp; cd traefik&lt;/code>&lt;/p>
&lt;h3 id="1-an-empty-letsencrypt-folder-mkdir-letsencrypt">1. An empty &lt;code>letsencrypt&lt;/code> folder: &lt;code>mkdir letsencrypt&lt;/code>&lt;/h3>
&lt;h3 id="2-an-empty-file-touch-dynamicyml-for-future-expansion">2. An empty file &lt;code>touch dynamic.yml&lt;/code> (for future expansion)&lt;/h3>
&lt;h3 id="3-the-static-config-nano-staticyml">3. The static config: &lt;code>nano static.yml&lt;/code>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">api&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">insecure&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">dashboard&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">providers&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">docker&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">exposedByDefault&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">entryPoints&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">web&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">address&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;:80&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">http2&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">maxConcurrentStreams&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">250&lt;/span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># fix for network error on the proxy to my immich instance&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">http3&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">advertisedPort&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">443&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># http:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># redirections:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># entryPoint:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># to: websecure&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># scheme: https&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">forwardedHeaders&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">trustedIPs&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">10.0.0.0&lt;/span>/8&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">172.16.0.0&lt;/span>/12&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">192.168.0.0&lt;/span>/16&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- fc00::/7&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">proxyProtocol&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">trustedIPs&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">10.0.0.0&lt;/span>/8&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">172.16.0.0&lt;/span>/12&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">192.168.0.0&lt;/span>/16&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">32&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- fc00::/7&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">33&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">websecure&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">34&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">address&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;:443&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">35&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">http2&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">36&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">maxConcurrentStreams&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">250&lt;/span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># fix for network error on the proxy to my immich instance&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">37&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">http3&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">38&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">advertisedPort&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">443&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">39&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">forwardedHeaders&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">40&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">trustedIPs&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">41&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">10.0.0.0&lt;/span>/8&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">42&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">172.16.0.0&lt;/span>/12&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">43&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">192.168.0.0&lt;/span>/16&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">44&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- fc00::/7&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">45&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">proxyProtocol&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">46&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">trustedIPs&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">47&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">10.0.0.0&lt;/span>/8&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">48&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">172.16.0.0&lt;/span>/12&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">49&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">192.168.0.0&lt;/span>/16&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">50&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- fc00::/7&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">51&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">52&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">certificatesResolvers&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">53&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">myresolver&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">54&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">acme&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">55&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">email&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;your-email-goes-here@tutorial.example&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">56&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">storage&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;/letsencrypt/acme.json&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">57&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">httpChallenge&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">58&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">entryPoint&lt;/span>:&lt;span style="color:#666"> &lt;/span>web&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Replace &lt;code>your-email-goes-here@tutorial.example&lt;/code> with your email address. Let&amp;rsquo;s Encrypt send you notifications when your ssl certificate expires.&lt;/p>
&lt;/blockquote>
&lt;h3 id="4-the-docker-compose-config-nano-composeyml">4. The docker compose config: &lt;code>nano compose.yml&lt;/code>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">services&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">traefik&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">image&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;traefik:v3.2&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">container_name&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;traefik&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">restart&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;always&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">ports&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;80:80&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;443:443&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">networks&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- pub&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">volumes&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;./letsencrypt:/letsencrypt&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;/var/run/docker.sock:/var/run/docker.sock:ro&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;./static.yml:/etc/traefik/traefik.yml:ro&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;./dynamic.yml:/etc/traefik/dynamic.yaml:ro&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">labels&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.dashboard.rule=Host(`example.com`) &amp;amp;&amp;amp; (PathPrefix(`/dashboard`) || PathPrefix(`/api/overview`) || PathPrefix(`/api/version`) || PathPrefix(`/api/http`) || PathPrefix(`/api/entrypoints`) || PathPrefix(`/api/tcp`) || PathPrefix(`/api/udp`))&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.dashboard.entrypoints=websecure&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.dashboard.tls.certresolver=myresolver&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.dashboard.service=api@internal&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># # if you want to password protect your traefik dashboard uncomment the following and change the user:pass&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic">#- &amp;#34;traefik.http.routers.dashboard.middlewares=auth&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic">#- &amp;#34;traefik.http.middlewares.auth.basicauth.users=&amp;#34; # to create user and pass: bash -c &amp;#39;echo $(htpasswd -nB admin) | sed -e s/\\$/\\$\\$/g&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">networks&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">pub&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">external&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Create the &lt;code>pub&lt;/code> network first using the command &lt;code>docker network create pub&lt;/code>&lt;/p>
&lt;p>Now we can start the traefik instance: &lt;code>docker compose up -d&lt;/code>&lt;/p>
&lt;h2 id="headscale">HeadScale&lt;/h2>
&lt;p>Let&amp;rsquo;s make a separate folder for headscale: &lt;code>cd .. &amp;amp;&amp;amp; mkdir headscale&lt;/code>&lt;/p>
&lt;h3 id="1-2-empty-folders-mkdir-data--mkdir-tailscale-client">1. 2 empty folders: &lt;code>mkdir data &amp;amp;&amp;amp; mkdir tailscale-client&lt;/code>&lt;/h3>
&lt;h3 id="2-the-headscale-config-nano-configyml">2. The headscale config: &lt;code>nano config.yml&lt;/code>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#447fcf;text-decoration:underline">---&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># The url clients will connect to.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">server_url&lt;/span>:&lt;span style="color:#666"> &lt;/span>https://example.com&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Address to listen to / bind to on the server&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">listen_addr&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">0.0.0.0&lt;/span>:&lt;span style="color:#3677a9">8080&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Address to listen to /metrics, you may want&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">metrics_listen_addr&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">127.0.0.1&lt;/span>:&lt;span style="color:#3677a9">9090&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 10&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 11&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Address to listen for gRPC.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 12&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">grpc_listen_addr&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">127.0.0.1&lt;/span>:&lt;span style="color:#3677a9">50443&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 13&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 14&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Allow the gRPC admin interface to run in INSECURE mode.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 15&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">grpc_allow_insecure&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 16&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 17&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">noise&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 18&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># The Noise private key is used to encrypt the traffic&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 19&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">private_key_path&lt;/span>:&lt;span style="color:#666"> &lt;/span>/var/lib/headscale/noise_private.key&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 20&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 21&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># List of IP prefixes to allocate tailaddresses from.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 22&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Each prefix consists of either an IPv4 or IPv6 address,&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 23&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">prefixes&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 24&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">v6&lt;/span>:&lt;span style="color:#666"> &lt;/span>fd7a:115c:a1e0::/48&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 25&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">v4&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">100.64.0.0&lt;/span>/10&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 26&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Strategy used for allocation of IPs to nodes, available options:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 27&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - sequential (default): assigns the next free IP from the previous given IP.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 28&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand).&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 29&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">allocation&lt;/span>:&lt;span style="color:#666"> &lt;/span>sequential&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 30&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 31&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># DERP is a relay system that Tailscale uses when a direct connection cannot be established.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 32&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">derp&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 33&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">server&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 34&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">enabled&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 35&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Region ID to use for the embedded DERP server.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 36&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">region_id&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">999&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 37&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">region_code&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;headscale&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 38&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">region_name&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;Headscale Embedded DERP&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 39&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Listens over UDP at the configured address for STUN connections - to help with NAT traversal.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 40&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">stun_listen_addr&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;0.0.0.0:3478&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 41&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Private key used to encrypt the traffic between headscale DERP and Tailscale clients.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 42&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">private_key_path&lt;/span>:&lt;span style="color:#666"> &lt;/span>/var/lib/headscale/derp_server_private.key&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 43&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># This flag can be used, so the DERP map entry for the embedded DERP server is not written automatically,&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 44&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">automatically_add_embedded_derp_region&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 45&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># For better connection stability (especially when using an Exit-Node and DNS is not working),&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 46&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">ipv4&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">1.2.3.4&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 47&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">ipv6&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">2001&lt;/span>:db8::1&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 48&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># List of externally available DERP maps encoded in JSON&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 49&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">urls&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 50&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- https://controlplane.tailscale.com/derpmap/default&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 51&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Locally available DERP map files encoded in YAML&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 52&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">paths&lt;/span>:&lt;span style="color:#666"> &lt;/span>[]&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 53&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># If enabled, a worker will be set up to periodically refresh the given sources and update the derpmap&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 54&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">auto_update_enabled&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 55&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># How often should we check for DERP updates?&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 56&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">update_frequency&lt;/span>:&lt;span style="color:#666"> &lt;/span>24h&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 57&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Disables the automatic check for headscale updates on startup&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 58&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">disable_check_updates&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 59&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Time before an inactive ephemeral node is deleted?&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 60&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">ephemeral_node_inactivity_timeout&lt;/span>:&lt;span style="color:#666"> &lt;/span>30m&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 61&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">database&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 62&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">type&lt;/span>:&lt;span style="color:#666"> &lt;/span>sqlite&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 63&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Enable debug mode. This setting requires the log.level to be set to &amp;#34;debug&amp;#34; or &amp;#34;trace&amp;#34;.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 64&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">debug&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 65&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">gorm&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 66&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">prepare_stmt&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 67&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">parameterized_queries&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 68&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">skip_err_record_not_found&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 69&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">slow_threshold&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">1000&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 70&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">sqlite&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 71&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">path&lt;/span>:&lt;span style="color:#666"> &lt;/span>/var/lib/headscale/db.sqlite&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 72&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">write_ahead_log&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 73&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 74&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic">### TLS configuration Let&amp;#39;s encrypt / ACME&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 75&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">acme_url&lt;/span>:&lt;span style="color:#666"> &lt;/span>https://acme-v02.api.letsencrypt.org/directory&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 76&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">acme_email&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;your-email-goes-here@tutorial.example&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 77&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">tls_letsencrypt_hostname&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 78&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Path to store certificates and metadata needed by letsencrypt&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 79&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">tls_letsencrypt_cache_dir&lt;/span>:&lt;span style="color:#666"> &lt;/span>/var/lib/headscale/cache&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 80&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 81&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Type of ACME challenge to use, currently supported types: HTTP-01 or TLS-ALPN-01&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 82&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">tls_letsencrypt_challenge_type&lt;/span>:&lt;span style="color:#666"> &lt;/span>HTTP-01&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 83&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># When HTTP-01 challenge is chosen, letsencrypt must set up a verification endpoint, and it will be listening on:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 84&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">tls_letsencrypt_listen&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;:http&amp;#34;&lt;/span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># :http = port 80&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 85&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">tls_cert_path&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 86&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">tls_key_path&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 87&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 88&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">log&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 89&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">format&lt;/span>:&lt;span style="color:#666"> &lt;/span>text&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># text or json&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 90&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">level&lt;/span>:&lt;span style="color:#666"> &lt;/span>info&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 91&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 92&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">policy&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 93&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">mode&lt;/span>:&lt;span style="color:#666"> &lt;/span>file&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 94&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">path&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 95&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 96&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">dns&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 97&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">magic_dns&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 98&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Defines the base domain to create the hostnames for MagicDNS.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 99&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">base_domain&lt;/span>:&lt;span style="color:#666"> &lt;/span>head.local&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">100&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">nameservers&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">101&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">global&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">102&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">1.1.1.1&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">103&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">1.0.0.1&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">104&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">2606&lt;/span>:&lt;span style="color:#3677a9">4700&lt;/span>:&lt;span style="color:#3677a9">4700&lt;/span>::&lt;span style="color:#3677a9">1111&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">105&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#3677a9">2606&lt;/span>:&lt;span style="color:#3677a9">4700&lt;/span>:&lt;span style="color:#3677a9">4700&lt;/span>::&lt;span style="color:#3677a9">1001&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">106&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">split&lt;/span>:&lt;span style="color:#666"> &lt;/span>{}&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">107&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">search_domains&lt;/span>:&lt;span style="color:#666"> &lt;/span>[]&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">108&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Extra DNS records&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">109&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">extra_records&lt;/span>:&lt;span style="color:#666"> &lt;/span>[]&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">110&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">111&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">unix_socket&lt;/span>:&lt;span style="color:#666"> &lt;/span>/var/run/headscale/headscale.sock&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">112&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">unix_socket_permission&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;0770&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">113&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">logtail&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">114&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># Enable logtail for this headscales clients.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">115&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">enabled&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">116&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#999;font-style:italic"># Enabling this option makes devices prefer a random port for WireGuard traffic over the default static port 41641.&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">117&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">randomize_client_port&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">false&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>It&amp;rsquo;s the default config, I removed some comments and replaced &lt;code>server_url&lt;/code>, &lt;code>acme_email&lt;/code> and the &lt;code>base_domain&lt;/code> from dns section. This last config is the Magic DNS that headscale uses to create a DNS entry for every device you connect to your tailscale vpn.&lt;/p>
&lt;/blockquote>
&lt;h3 id="3-the-docker-compose-config-nano-composeyml">3. The docker compose config: &lt;code>nano compose.yml&lt;/code>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">services&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">headscale&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">container_name&lt;/span>:&lt;span style="color:#666"> &lt;/span>headscale&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">image&lt;/span>:&lt;span style="color:#666"> &lt;/span>headscale/headscale&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">command&lt;/span>:&lt;span style="color:#666"> &lt;/span>serve&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">restart&lt;/span>:&lt;span style="color:#666"> &lt;/span>always&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">ports&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;8080:8080&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">networks&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- pub&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">volumes&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;./data:/var/lib/headscale&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;./config.yml:/etc/headscale/config.yaml&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">cap_add&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- NET_ADMIN&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- SYS_MODULE&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">sysctls&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- net.ipv4.ip_forward=1&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- net.ipv4.conf.all.src_valid_mark=1&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">labels&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.headscale.rule=Host(`example.com`)&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.headscale.entrypoints=websecure&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.headscale.tls.certresolver=myresolver&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.services.headscale.loadbalancer.server.port=8080&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">headplane&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">container_name&lt;/span>:&lt;span style="color:#666"> &lt;/span>headplane&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">image&lt;/span>:&lt;span style="color:#666"> &lt;/span>ghcr.io/tale/headplane:0.3.2&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">restart&lt;/span>:&lt;span style="color:#666"> &lt;/span>unless-stopped&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">32&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">ports&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">33&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#39;3000:3000&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">34&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">networks&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">35&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- pub&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">36&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">depends_on&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">37&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- headscale&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">38&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">volumes&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">39&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;./config.yml:/etc/headscale/config.yaml&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">40&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">environment&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">41&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">HEADSCALE_URL&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;http://headscale:8080&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">42&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">API_KEY&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">43&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">CONFIG_FILE&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;/etc/headscale/config.yaml&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">44&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">COOKIE_SECRET&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;put-some-random-string-here-32j564b64kl6n34lk&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">45&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">DISABLE_API_KEY_LOGIN&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;true&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">46&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">COOKIE_SECURE&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;false&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">47&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">HOST&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;0.0.0.0&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">48&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">PORT&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;3000&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">49&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">labels&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">50&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.enable=true&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">51&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.headplane.rule=Host(`example.com`) &amp;amp;&amp;amp; PathPrefix(`/admin`)&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">52&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.headplane.entrypoints=websecure&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">53&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.routers.headplane.tls.certresolver=myresolver&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">54&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#34;traefik.http.services.headplane.loadbalancer.server.port=3000&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">55&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic">#- &amp;#34;traefik.http.routers.headplane.middlewares=auth&amp;#34; # uncomment this only if you generated a password in traefik step 4&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">56&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">57&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># client:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">58&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># container_name: tailscale-client&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">59&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># image: tailscale/tailscale&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">60&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># restart: unless-stopped&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">61&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># environment:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">62&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - &amp;#34;TS_AUTHKEY=&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">63&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - &amp;#34;TS_STATE_DIR=/var/lib/tailscale&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">64&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - &amp;#34;TS_USERSPACE=false&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">65&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - &amp;#34;TS_EXTRA_ARGS=--login-server=https://example.com --advertise-exit-node --hostname=server-client --shields-up=false&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">66&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># networks:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">67&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - pub&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">68&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># volumes:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">69&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - &amp;#34;./tailscale-client:/var/lib/tailscale&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">70&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - &amp;#34;/dev/net/tun:/dev/net/tun&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">71&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># cap_add:&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">72&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - net_admin&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">73&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># - sys_module&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">74&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">75&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">networks&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">76&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">pub&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">77&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">external&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">true&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can start headscale now: &lt;code>docker compose up -d&lt;/code>&lt;/p>
- https://telteu.ro/posts/headscale-with-traefik/ - Andrei Telteu 2024</description></item><item><title>Should you self-host open-source services or pay for hosted versions ?</title><link>https://telteu.ro/posts/selfhost-vs-hosted-saas/</link><pubDate>Fri, 22 Nov 2024 00:04:22 +0000</pubDate><guid>https://telteu.ro/posts/selfhost-vs-hosted-saas/</guid><description>Andrei Telteu https://telteu.ro/posts/selfhost-vs-hosted-saas/ -&lt;blockquote>
&lt;p>Featured image by ChatGPT/DALL-E&lt;/p>
&lt;/blockquote>
&lt;p>I was watching this video on using a paid hosted version of an open-source software instead of self-hosting it:&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/TkysPcpK0aQ?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"
>&lt;/iframe>
&lt;/div>
&lt;p>There are both benefits and risks to each approach that you should take in consideration when you make a choice like this.&lt;/p>
&lt;p>This also depends on how this service affects your business:&lt;/p>
&lt;p>&lt;strong>A.&lt;/strong> If this service is &lt;strong>critical to your business&lt;/strong>: (like for example the in browser IDE that the above video mentions for his e-learning platform)&lt;/p>
&lt;ul>
&lt;li>you should &lt;strong>self host&lt;/strong> if possible.&lt;/li>
&lt;li>you should &lt;strong>know&lt;/strong> the ins and outs of. Gain as much knowledge as you can.&lt;/li>
&lt;li>you should &lt;strong>spend as much time as needed&lt;/strong> for this integration to be &lt;strong>frictionless and perfect&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Arguments&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>This is the &lt;strong>core&lt;/strong> of your business ! It should be the feature that &lt;strong>differentiates&lt;/strong> you from any other competitor.&lt;/li>
&lt;li>If something goes wrong and you have to change this service, there will be a &lt;strong>very high impact&lt;/strong> on your customers. Maybe you can&amp;rsquo;t find a good enough alternative, or one with the same features/customizations. The vendor lock-in here has a high impact.&lt;/li>
&lt;li>You are free to change/improove any of the features of said service given enough dev time and a permissive code license.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>B.&lt;/strong> If the service is &lt;strong>not&lt;/strong> critical: (like your support ticket system, chat support, invoicing system, payment provider, knowledge base, blog, license management, etc)&lt;/p>
&lt;ul>
&lt;li>you should use a hosted version / Software As A Service / external solution.&lt;/li>
&lt;li>you should spend as little time as needed.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Arguments&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>It it not the core of your business, it does not matter that much.&lt;/li>
&lt;li>If something goes wrong and you have to change this service there will be very little impact on your customers. Many of them won&amp;rsquo;t even notice. If you can&amp;rsquo;t find an alternative with the same features, it doesn&amp;rsquo;t matter that much.&lt;/li>
&lt;/ul>
&lt;h2 id="the-risks-involved-for-hosted-versions--saas">The &lt;strong>risks&lt;/strong> involved for hosted versions / SaaS&lt;/h2>
&lt;p>I want to present to you some scenarios in which the hosted version can affect your startup:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The external company can go bankrupt and you have to migrate off it as quick as possible.
&lt;br/>You don&amp;rsquo;t know their financial situation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The external company can focus on a new product and deprecate / stop support for your version.
&lt;br/>You don&amp;rsquo;t know their roadmap.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>When you evolve and want to add/improve a feature you are limited to the customization provider and the external prover&amp;rsquo;s willingness to work with you to change something for you.
&lt;br/>This can change over time as you grow or your external provider grows.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The external company can shift its focus on enterprise and increase prices overnight by 100x.
&lt;br/>You don&amp;rsquo;t know their leadership.
&lt;br/>For example this
&lt;a href="https://robindev.substack.com/p/cloudflare-took-down-our-website" target="_blank" rel="noopener">120k$ forced bill from CloudFlare&lt;/a>
(
&lt;a href="https://www.youtube.com/watch?v=8zj7ei5Egk8" target="_blank" rel="noopener">ThePrimeagen video here&lt;/a>
)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The external company can get hacked and your customers data can be leaked. Even if the external service does not host any of your customers data, if they get hacked, the bad actor can modify the service to steal customers data without you taking any action (like upgrading a npm dependency like in the case of a supply chain attack).
&lt;br/>You don&amp;rsquo;t know the security measures that all your external services apply to their business.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>When the external provider of one of your &lt;strong>CORE&lt;/strong> features has an outage, you have an outage that you can&amp;rsquo;t do anything about.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="the-benefits-of-self-hosting-">The benefits of &lt;strong>Self-Hosting&lt;/strong> !&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>When you need a feature/customization that is not supported by your external solution: you just fork it and invest dev time into it. (If the license supports it)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>When something breaks, code regression: you have the power to rollback. You don&amp;rsquo;t have to wait for the external provider to fix it.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>When you have an outage because of a bad config: you have the power to fix it and change your deployment procedure to never happen again.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>When you have an outage because of your hosting provider: you can change your hosting.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>My point is that the CORE features of your business should be as close to your control as possible.
Too many external dependencies increase your overall risk because companies are not your buddies from high school, companies evolve, companies change, companies get bought out, companies get hacked, and so on.&lt;/p>
&lt;p>For your startup the risks are worth the time saved ?
&lt;br/>At the stage you are at ?
&lt;br/>What about at a later stage ?&lt;/p>
- https://telteu.ro/posts/selfhost-vs-hosted-saas/ - Andrei Telteu 2024</description></item><item><title>MiniPC rack Part 1: the pc and case</title><link>https://telteu.ro/posts/minipc-rack-part-1/</link><pubDate>Tue, 19 Nov 2024 00:16:30 +0000</pubDate><guid>https://telteu.ro/posts/minipc-rack-part-1/</guid><description>Andrei Telteu https://telteu.ro/posts/minipc-rack-part-1/ -&lt;h2 id="hardware">Hardware&lt;/h2>
&lt;p>I was looking start my homelab with a mini pc and I finally found a good deal on the second hand market:&lt;/p>
&lt;p>HP EliteDesk 705 G4 with AMD Ryzen 5 2400GE, &lt;strong>16GB&lt;/strong> RAM DDR4 2666 Mhz (sodimm/laptop), with 90W power supply for only &lt;strong>450 lei (~90€ / ~95$)&lt;/strong>.&lt;/p>
&lt;p>It offers a very good price to performance ratio because the CPU has &lt;strong>4 cores 8 threads at 3.8 GHz&lt;/strong>. The CPU performance is the most important thing for me.
&lt;br>I got one for testing, and then I get 2 more:&lt;/p>
&lt;p>
&lt;a href="https://telteu.ro/posts/minipc-rack-part-1/minipcs-horizontal.b398660b22bde58bceace0fd595c4de2.jpg" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/minipc-rack-part-1/minipcs-horizontal_hu2609188977948449556.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/minipc-rack-part-1/minipcs-horizontal.b398660b22bde58bceace0fd595c4de2.jpg" alt="minipcs" loading="lazy" height="930" width="3961" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>Then I found another deal for TeamGroup 512 GB NVMe M.2 SSD for only &lt;strong>120 lei (~24€ / ~25$)&lt;/strong> (new/sealed).&lt;/p>
&lt;p>
&lt;a href="https://telteu.ro/posts/minipc-rack-part-1/ssds.1fe86705afcbc2c58ecb6ae4aa1c75fe.jpeg" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/minipc-rack-part-1/ssds_hu7805926632893103691.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/minipc-rack-part-1/ssds.1fe86705afcbc2c58ecb6ae4aa1c75fe.jpeg" alt="ssd image" loading="lazy" height="933" width="1874" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>&lt;strong>Perfect !&lt;/strong>&lt;/p>
&lt;h2 id="software">Software&lt;/h2>
&lt;p>I started researching for a good and free VM hypervisor, easy enough to configure and use.
&lt;br/>I tried out
&lt;a href="https://www.proxmox.com/" target="_blank" rel="noopener">Proxmox&lt;/a>
but then I found
&lt;a href="https://xcp-ng.org/" target="_blank" rel="noopener">XCP-NG&lt;/a>
with
&lt;a href="https://xen-orchestra.com/" target="_blank" rel="noopener">XEN Orchestra&lt;/a>
on
&lt;a href="https://youtube.com/playlist?list=PLjGQNuuUzvmsrt8VrocFvN2DaZlwk8sgz&amp;amp;si=p8WJCt4I9TRDOrgO" target="_blank" rel="noopener">Lawrence Systems&amp;rsquo;s youtube channel&lt;/a>
and the search was over. It has multiple features that convinced me it is the best choice for me:&lt;/p>
&lt;ul>
&lt;li>Free and open source&lt;/li>
&lt;li>User interface easy and somewhat similar to VPS providers&amp;rsquo;s interfaces&lt;/li>
&lt;li>Ability to replicate and migrate VMs on different hosts&lt;/li>
&lt;li>Snapshots&lt;/li>
&lt;/ul>
&lt;h2 id="3d-printing-the-case">3D Printing the case&lt;/h2>
&lt;p>After a while I found a good deal on a 3D Printer and I started learning how to 3D print, mess around with settings, then I learned how to model basic small and simple parts.&lt;/p>
&lt;p>I started searching around on
&lt;a href="https://www.yeggi.com/" target="_blank" rel="noopener">yeggi.com&lt;/a>
(search engine for 3D models) for compatible cases for this MiniPC and I found the best one:&lt;/p>
&lt;p>
&lt;a href="https://www.printables.com/model/827617-hp-mini-staggered-rack-mount" target="_blank" rel="noopener">&amp;ldquo;HP Mini Staggered Rack Mount&amp;rdquo; by @dsluo_362876&lt;/a>
&lt;/p>
&lt;p>
&lt;a href="https://telteu.ro/posts/minipc-rack-part-1/minipc-case-model.69a466ada23ca1f6a9bb70391120309a.jpg" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/minipc-rack-part-1/minipc-case-model_hu17320638519990072788.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/minipc-rack-part-1/minipc-case-model.69a466ada23ca1f6a9bb70391120309a.jpg" alt="minipc case model image" loading="lazy" height="1357" width="2432" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>The idea is great: incorporate the MiniPC and it&amp;rsquo;s power supply in the same case. The execution is great ! The model is very good quality.&lt;/p>
&lt;p>One problem: My 3D printer BambuLab A1 Mini has a small bed size at 180x180x180 mm and I have to rotate the model at 45 degrees, and cut the very thick top part of the case.&lt;/p>
&lt;p>
&lt;a href="https://telteu.ro/posts/minipc-rack-part-1/model-too-big.f7d9a2a5a92c9651436d1911a94a0700.png" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/minipc-rack-part-1/model-too-big_hu5611133157586873853.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/minipc-rack-part-1/model-too-big.f7d9a2a5a92c9651436d1911a94a0700.png" alt="model too big" loading="lazy" height="721" width="1220" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>&lt;strong>Problem solved&lt;/strong> ! It fits perfectly in the bed ! It&amp;rsquo;s print time !&lt;/p>
&lt;p>I stopped the print after 2-3 cm just to make some fitment checks make sure I dont print the whole thing for nothing it it does not fit.
&lt;br/>This is a very &lt;strong>good practice&lt;/strong> and I recommend you do the same !
&lt;br/>Good thing I did this because I found out that &lt;strong>the power supply I have is bigger in every dimension&lt;/strong> than the one the author had. He wrote the power supply dimensions in the model description but I did not read it.&lt;/p>
&lt;p>I&amp;rsquo;m stuck! I need to modify the model to fit my power supply but I don&amp;rsquo;t know how to do it and I don&amp;rsquo;t have the source files, I only have the STL mesh file.&lt;/p>
&lt;p>&lt;strong>To be continued&amp;hellip;&lt;/strong> check part 2&lt;/p>
- https://telteu.ro/posts/minipc-rack-part-1/ - Andrei Telteu 2024</description></item><item><title>How to control a Noctua PWM fan from Raspberry Pi</title><link>https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/</link><pubDate>Mon, 18 Nov 2024 00:14:52 +0200</pubDate><guid>https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/</guid><description>Andrei Telteu https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/ -&lt;p>
&lt;a href="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pwm-pi-ezgif.com-optimize.e400dfe08b35d68aee56e4e16fae8785.gif" class="fancybox">
&lt;picture>
&lt;img class="img-fluid" src="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pwm-pi-ezgif.com-optimize.e400dfe08b35d68aee56e4e16fae8785.gif" alt="Noctua NF-A20 PWM fan" loading="lazy" height="895" width="1711" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>I am making
&lt;a href="https://telteu.ro/posts/minipc-rack-part-1/">my homelab&lt;/a>
and I need to control the
&lt;a href="https://noctua.at/en/nf-a20-pwm-chromax-black-swap" target="_blank" rel="noopener">Noctua NF-A20 PWM chromax.black.swap 200x200mm&lt;/a>
fan from Raspberry Pi, and this is how I&amp;rsquo;ve done it.&lt;/p>
&lt;h2 id="parts-you-need">Parts you need:&lt;/h2>
&lt;ul>
&lt;li>Some Raspberry Pi&lt;/li>
&lt;li>The Noctua NF-A20 PWM fan (should work with other 12V noctua fans as well)&lt;/li>
&lt;li>A multimeter&lt;/li>
&lt;li>
&lt;a href="https://www.amazon.com/Adjustable-Converter-Transformer-Regulator-3-5V-35V/dp/B092CJBL92" target="_blank" rel="noopener">LM2577 DC-DC Step Up Booster Converter&lt;/a>
&lt;/li>
&lt;li>
&lt;a href="https://www.amazon.com/ALLECIN-2N2222-Amplifier-Transistors-Transistor/dp/B0CBK1T5FQ" target="_blank" rel="noopener">NPN Transistor&lt;/a>
&lt;/li>
&lt;li>1K Ohm Resistor&lt;/li>
&lt;/ul>
&lt;h2 id="diagram">Diagram:&lt;/h2>
&lt;p>
&lt;a href="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/diagram.6b98eb62e389136c2a1f5c245243f014.png" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/diagram_hu240544990833317495.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/diagram.6b98eb62e389136c2a1f5c245243f014.png" alt="diagram image" loading="lazy" height="1824" width="1883" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;h2 id="lets-start-from-the-pi">Let&amp;rsquo;s start from the Pi:&lt;/h2>
&lt;p>1- Connect a wire from GPIO pin 16, or any simple gpio pin, to the 1k resistor, and then the other end of the transistor to the middle pin of the transistor.&lt;/p>
&lt;p>2- A wire from the right pin of the transistor to any ground pin of the Pi. The face of the transistor is the flat one.&lt;/p>
&lt;p>3- A wire from the left pin of the transistor to the &amp;ldquo;IN-&amp;rdquo; 5V negative input of the power convertor.&lt;/p>
&lt;p>4- A wire from one of the 5V Pi pins (top right) to the &amp;ldquo;IN+&amp;rdquo; 5V positive input of the power convertor.&lt;/p>
&lt;p>5- &lt;strong>Important&lt;/strong>: adjust the converter to 12V or lower.
&lt;br/>Do NOT connect the fan right now because you can permanently damage it because of high voltage.
&lt;br/>    A- Turn on the converter by connecting a ground pin from the Pi directly to the Power Converter&amp;rsquo;s &amp;ldquo;IN-&amp;rdquo; connector OR by runing the code from the next section and just calling &lt;code>speed(fan, 100) / time.sleep(180)&lt;/code>.
&lt;br/>    B- Connect a multimeter to the converter&amp;rsquo;s &amp;ldquo;OUT+&amp;rdquo; and &amp;ldquo;OUT-&amp;rdquo; and select voltage measurement on the multimeter (usually marked as &amp;ldquo;2V&amp;rdquo;).
&lt;br/>    C- On the converter turn the small yellow screw until the multimeter shows 12V or a bit smaller to be safe. I have mine at 11.5V.&lt;/p>
&lt;p>
&lt;a href="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/power-converter-nob.09666e2f6a0cb904a3d9dbb80a0fa25b.png" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/power-converter-nob_hu2864229298055400022.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/power-converter-nob.09666e2f6a0cb904a3d9dbb80a0fa25b.png" alt="power converter adjustment nob" loading="lazy" height="255" width="999" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>    D- When you are done disconnect the multimeter and the ground wire, or turn off the script.&lt;/p>
&lt;p>The pinout from the noctua fan I found here:
&lt;a href="https://faqs.noctua.at/en/support/solutions/articles/101000081757-what-pin-configuration-do-noctua-fans-use-" target="_blank" rel="noopener">https://faqs.noctua.at/en/support/solutions/articles/101000081757-what-pin-configuration-do-noctua-fans-use-&lt;/a>
&lt;a href="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pinout.db5471cf55cd488e3de87f4205f2f44e.png" class="fancybox">
&lt;picture>
&lt;source srcset="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pinout_hu15230658805204666452.webp" type="image/webp" />
&lt;img class="img-fluid" src="https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pinout.db5471cf55cd488e3de87f4205f2f44e.png" alt="noctua pinout image" loading="lazy" height="160" width="1037" />
&lt;/picture>
&lt;/a>&lt;/p>
&lt;p>5- Wire from power convertor &amp;ldquo;OUT-&amp;rdquo; (12V negative) to noctua pin 1.&lt;/p>
&lt;p>6- Wire from power convertor &amp;ldquo;OUT+&amp;rdquo; (12V positive) to noctua pin 2.&lt;/p>
&lt;p>5- Wire from noctua pin 4 to Pi GPIO pin 12.
&lt;a href="https://pinout.xyz/pinout/pin32_gpio12/" target="_blank" rel="noopener">This pin has PWM capability&lt;/a>
.&lt;/p>
&lt;h2 id="the-code">The code:&lt;/h2>
&lt;p>I used the code from this
&lt;a href="https://www.the-diy-life.com/connecting-a-pwm-fan-to-a-raspberry-pi/" target="_blank" rel="noopener">tutorial published on the-diy-life.com by Michael Klements&lt;/a>
(
&lt;a href="https://github.com/mklements/PWMFanControl/blob/main/FanProportional.py" target="_blank" rel="noopener">original code&lt;/a>
), and I modified it to use the transistor to turn off the fan, because the fan PWM does not scale down to 0 RPM. The
&lt;a href="https://noctua.at/en/nf-a20-pwm-chromax-black-swap/specification" target="_blank" rel="noopener">minimum rotational speed is 20%&lt;/a>
(350RPM).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> &lt;span style="color:#447fcf;text-decoration:underline">RPi.GPIO&lt;/span> &lt;span style="color:#6ab825;font-weight:bold">as&lt;/span> &lt;span style="color:#447fcf;text-decoration:underline">GPIO&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> &lt;span style="color:#447fcf;text-decoration:underline">time&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> &lt;span style="color:#447fcf;text-decoration:underline">signal&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> &lt;span style="color:#447fcf;text-decoration:underline">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic"># The Noctua PWM control actually wants 25 kHz (kilo!), see page 6 on:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic"># https://noctua.at/pub/media/wysiwyg/Noctua_PWM_specifications_white_paper.pdf&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>PWM_FREQ = &lt;span style="color:#3677a9">25&lt;/span> &lt;span style="color:#999;font-style:italic"># [Hz] PWM frequency&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>FAN_PIN = &lt;span style="color:#3677a9">12&lt;/span> &lt;span style="color:#999;font-style:italic"># BCM pin used to drive PWM fan&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>TRAN_PIN = &lt;span style="color:#3677a9">16&lt;/span> &lt;span style="color:#999;font-style:italic"># NPN Transistor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">def&lt;/span> &lt;span style="color:#447fcf">speed&lt;/span>(fan, percent):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span> &lt;span style="color:#24909d">print&lt;/span>(&lt;span style="color:#ed9d13">&amp;#34;set fan to&amp;#34;&lt;/span>, percent)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> (percent &amp;lt; &lt;span style="color:#3677a9">20&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span> GPIO.output(TRAN_PIN, &lt;span style="color:#6ab825;font-weight:bold">False&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span> fan.ChangeDutyCycle(&lt;span style="color:#3677a9">20&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span> GPIO.output(TRAN_PIN, &lt;span style="color:#6ab825;font-weight:bold">True&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span> fan.ChangeDutyCycle(percent)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span> signal.signal(signal.SIGTERM, &lt;span style="color:#6ab825;font-weight:bold">lambda&lt;/span> *args: sys.exit(&lt;span style="color:#3677a9">0&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span> GPIO.setwarnings(&lt;span style="color:#6ab825;font-weight:bold">True&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span> GPIO.setmode(GPIO.BCM)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span> GPIO.setup(TRAN_PIN, GPIO.OUT)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span> GPIO.setup(FAN_PIN, GPIO.OUT, initial=GPIO.LOW)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span> fan = GPIO.PWM(FAN_PIN, PWM_FREQ)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic"># do a few cycles just for testing&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span> speed(fan, &lt;span style="color:#3677a9">100&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">32&lt;/span>&lt;span> time.sleep(&lt;span style="color:#3677a9">30&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">33&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">34&lt;/span>&lt;span> speed(fan, &lt;span style="color:#3677a9">50&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">35&lt;/span>&lt;span> time.sleep(&lt;span style="color:#3677a9">30&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">36&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">37&lt;/span>&lt;span> speed(fan, &lt;span style="color:#3677a9">0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">38&lt;/span>&lt;span> time.sleep(&lt;span style="color:#3677a9">30&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">39&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">40&lt;/span>&lt;span> speed(fan, &lt;span style="color:#3677a9">20&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">41&lt;/span>&lt;span> time.sleep(&lt;span style="color:#3677a9">30&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">42&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">43&lt;/span>&lt;span> speed(fan, &lt;span style="color:#3677a9">70&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">44&lt;/span>&lt;span> time.sleep(&lt;span style="color:#3677a9">30&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">45&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">46&lt;/span>&lt;span> speed(fan, &lt;span style="color:#3677a9">100&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">47&lt;/span>&lt;span> time.sleep(&lt;span style="color:#3677a9">30&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">48&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">49&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">except&lt;/span> &lt;span style="color:#bbb">KeyboardInterrupt&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">50&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">51&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">52&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">finally&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">53&lt;/span>&lt;span> GPIO.cleanup()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Done. Happy tinkering !&lt;/p>
- https://telteu.ro/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/ - Andrei Telteu 2024</description></item><item><title>How to Use Templ With Goravel</title><link>https://telteu.ro/posts/how-to-use-templ-with-goravel/</link><pubDate>Mon, 18 Nov 2024 00:12:52 +0200</pubDate><guid>https://telteu.ro/posts/how-to-use-templ-with-goravel/</guid><description>Andrei Telteu https://telteu.ro/posts/how-to-use-templ-with-goravel/ -&lt;h2 id="install-the-framework-and-tools">Install the framework and tools&lt;/h2>
&lt;p>First let&amp;rsquo;s install
&lt;a href="https://goravel.dev/" target="_blank" rel="noopener">Goravel&lt;/a>
. It&amp;rsquo;s a batteries included Go Web Framework for developers familiar with the Laravel Framework.&lt;/p>
&lt;p>Steps from
&lt;a href="https://github.com/goravel/docs/blob/master/getting-started/installation.md" target="_blank" rel="noopener">Getting started documentation&lt;/a>
:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>// Download framework
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>git clone https://github.com/goravel/goravel.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>rm -rf goravel/.git*
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>// Install dependencies
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#24909d">cd&lt;/span> goravel
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>go mod tidy
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>// Create .env environment configuration file
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>cp .env.example .env
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>// Generate application key
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>go run . artisan key:generate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now install
&lt;a href="https://templ.guide/quick-start/installation" target="_blank" rel="noopener">templ&lt;/a>
for html templates and
&lt;a href="https://github.com/cosmtrek/air?tab=readme-ov-file#installation" target="_blank" rel="noopener">air&lt;/a>
for hot reloading:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>go install github.com/a-h/templ/cmd/templ@latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span>go install github.com/cosmtrek/air@latest
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="configure-a-simple-frontend-template-structure">Configure a simple frontend template structure&lt;/h2>
&lt;p>(work in progress - I will update with global variables and script push)&lt;/p>
&lt;p>• Add this line in your &lt;code>/.gitignore&lt;/code> file: &lt;code>*_templ.go&lt;/code>&lt;/p>
&lt;p>• Delete &lt;code>resources/views/welcome.tmpl&lt;/code>&lt;/p>
&lt;p>• Create 2 folders in &lt;code>resources/views&lt;/code>, &lt;code>home&lt;/code> and &lt;code>parts&lt;/code>&lt;/p>
&lt;p>• In the folder &lt;code>resources/views/parts&lt;/code> create 3 files:&lt;/p>
&lt;p>   1. &lt;code>resources/views/parts/header.templ&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> parts
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span>templ &lt;span style="color:#447fcf">Header&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">4&lt;/span>&lt;span> &amp;lt;h1&amp;gt;Header&amp;lt;/h1&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">5&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>   2. &lt;code>resources/views/parts/footer.templ&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> parts
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span>templ &lt;span style="color:#447fcf">Footer&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">4&lt;/span>&lt;span> &amp;lt;footer&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">5&lt;/span>&lt;span> &amp;lt;p&amp;gt;&amp;amp;copy; &lt;span style="color:#3677a9">2024&lt;/span> MyProject&amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">6&lt;/span>&lt;span> &amp;lt;/footer&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">7&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>   3. &lt;code>resources/views/parts/template.templ&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> parts
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>templ &lt;span style="color:#447fcf">Template&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span> &amp;lt;!DOCTYPE html&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span> &amp;lt;html&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span> &amp;lt;head&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span> &amp;lt;title&amp;gt;My Page&amp;lt;/title&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span> &amp;lt;meta charset=&lt;span style="color:#ed9d13">&amp;#34;utf-8&amp;#34;&lt;/span>/&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> &amp;lt;meta http-equiv=&lt;span style="color:#ed9d13">&amp;#34;Content-Type&amp;#34;&lt;/span> content=&lt;span style="color:#ed9d13">&amp;#34;text/html; charset=utf-8&amp;#34;&lt;/span>/&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span> &amp;lt;meta name=&lt;span style="color:#ed9d13">&amp;#34;viewport&amp;#34;&lt;/span> content=&lt;span style="color:#ed9d13">&amp;#34;width=device-width, initial-scale=1&amp;#34;&lt;/span>/&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span> &amp;lt;!-- Your styles &lt;span style="color:#6ab825;font-weight:bold">go&lt;/span> here --&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span> &amp;lt;/head&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span> &amp;lt;body&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span> &lt;span style="color:#a61717;background-color:#e3d2d2">@&lt;/span>&lt;span style="color:#447fcf">Header&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span> { children... }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span> &lt;span style="color:#a61717;background-color:#e3d2d2">@&lt;/span>&lt;span style="color:#447fcf">Footer&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span> &amp;lt;!-- Your scripts &lt;span style="color:#6ab825;font-weight:bold">go&lt;/span> here --&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span> &amp;lt;script src=&lt;span style="color:#ed9d13">&amp;#34;//unpkg.com/alpinejs&amp;#34;&lt;/span> &lt;span style="color:#6ab825;font-weight:bold">defer&lt;/span>&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span> &amp;lt;/body&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span> &amp;lt;/html&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>• Create your homepage component: &lt;code>resources/views/home/index.templ&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> home
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;goravel/resources/views/parts&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>templ &lt;span style="color:#447fcf">Index&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span> &lt;span style="color:#a61717;background-color:#e3d2d2">@&lt;/span>parts.&lt;span style="color:#447fcf">Template&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span> &amp;lt;h1&amp;gt;Homepage&amp;lt;/h1&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span> &amp;lt;div&amp;gt;Templ is awesome&amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Their documentation for
&lt;a href="https://templ.guide/syntax-and-usage/template-composition" target="_blank" rel="noopener">children components is here&lt;/a>
. They have an example for a layout structure but I find this method better.&lt;/p>
&lt;h2 id="use-this-homepage-component-in-your-controller">Use this homepage component in your controller&lt;/h2>
&lt;p>I made this new file &lt;code>app/http/controllers/controller.go&lt;/code> where I can store some helpers available to any controller.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> controllers
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span> &lt;span style="color:#ed9d13">&amp;#34;github.com/a-h/templ&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span> &lt;span style="color:#ed9d13">&amp;#34;github.com/goravel/framework/contracts/http&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">func&lt;/span> &lt;span style="color:#447fcf">RenderTempl&lt;/span>(c http.Context, comp templ.Component) http.Response {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> c.&lt;span style="color:#447fcf">Response&lt;/span>().&lt;span style="color:#447fcf">Status&lt;/span>(&lt;span style="color:#3677a9">200&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span> c.&lt;span style="color:#447fcf">Response&lt;/span>().&lt;span style="color:#447fcf">Header&lt;/span>(&lt;span style="color:#ed9d13">&amp;#34;Content-Type&amp;#34;&lt;/span>, &lt;span style="color:#ed9d13">&amp;#34;text/html&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span> comp.&lt;span style="color:#447fcf">Render&lt;/span>(c, c.&lt;span style="color:#447fcf">Response&lt;/span>().&lt;span style="color:#447fcf">Writer&lt;/span>())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> &lt;span style="color:#6ab825;font-weight:bold">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This helper renders the provided templ component in the response buffer along with a 200 status header.
Let&amp;rsquo;s use it in &lt;code>app/http/controllers/home_controller.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> controllers
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span> &lt;span style="color:#ed9d13">&amp;#34;goravel/resources/views/home&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span> &lt;span style="color:#ed9d13">&amp;#34;github.com/goravel/framework/contracts/http&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">type&lt;/span> HomeController &lt;span style="color:#6ab825;font-weight:bold">struct&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">//Dependent services
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">func&lt;/span> &lt;span style="color:#447fcf">NewHomeController&lt;/span>() *HomeController {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> &amp;amp;HomeController{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">//Inject services
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">func&lt;/span> (r *HomeController) &lt;span style="color:#447fcf">Index&lt;/span>(ctx http.Context) http.Response {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">// doing awesome stuff here
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">&lt;/span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> &lt;span style="color:#447fcf">RenderTempl&lt;/span>(ctx, home.&lt;span style="color:#447fcf">Index&lt;/span>())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now set this new route:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">package&lt;/span> routes
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span> &lt;span style="color:#ed9d13">&amp;#34;goravel/app/http/controllers&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span> &lt;span style="color:#ed9d13">&amp;#34;github.com/goravel/framework/facades&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">func&lt;/span> &lt;span style="color:#447fcf">Web&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> homeController := controllers.&lt;span style="color:#447fcf">NewHomeController&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span> facades.&lt;span style="color:#447fcf">Route&lt;/span>().&lt;span style="color:#447fcf">Get&lt;/span>(&lt;span style="color:#ed9d13">&amp;#34;/&amp;#34;&lt;/span>, homeController.Index)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="configure-hot-reloading-with-air">Configure hot reloading with Air&lt;/h2>
&lt;p>Goravel already comes with the configuration file (&lt;code>.air.toml&lt;/code>) you need for this, we only need to add the &lt;code>templ generate&lt;/code> command in the cmd parameter, like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>[build]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span> bin = &amp;#34;./storage/temp/main&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span>&lt;span style="color:#d22323">- cmd = &amp;#34;go build -o ./storage/temp/main .&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">4&lt;/span>&lt;span>&lt;span style="color:#d22323">&lt;/span>&lt;span style="color:#589819">+ cmd = &amp;#34;templ generate &amp;amp;&amp;amp; go build -o ./storage/temp/main .&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you are using Windows add &lt;code>.exe&lt;/code> to main in both &lt;code>bin&lt;/code> and &lt;code>cmd&lt;/code> parameters:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>[build]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span> bin = &lt;span style="color:#ed9d13">&amp;#34;./storage/temp/main.exe&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span> cmd = &lt;span style="color:#ed9d13">&amp;#34;templ generate &amp;amp;&amp;amp; go build -o ./storage/temp/main.exe .&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Done ! Happy coding !&lt;/p>
- https://telteu.ro/posts/how-to-use-templ-with-goravel/ - Andrei Telteu 2024</description></item><item><title>Docker Compose helper script</title><link>https://telteu.ro/posts/docker-compose-helper-script/</link><pubDate>Mon, 18 Nov 2024 00:10:52 +0200</pubDate><guid>https://telteu.ro/posts/docker-compose-helper-script/</guid><description>Andrei Telteu https://telteu.ro/posts/docker-compose-helper-script/ -&lt;p>Make a new file at the root folder called &lt;code>dc&lt;/code> without extension.&lt;/p>
&lt;p>Content example. Modify for your needs.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#cd2828;font-weight:bold">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#cd2828;font-weight:bold">&lt;/span>&lt;span style="color:#24909d">trap&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;exit&amp;#34;&lt;/span> &lt;span style="color:#3677a9">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#40ffff">DC&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;docker compose&amp;#34;&lt;/span> &lt;span style="color:#999;font-style:italic"># add `-f docker/compose.yml` if it&amp;#39;s in another folder&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [ &lt;span style="color:#40ffff">$#&lt;/span> -eq &lt;span style="color:#3677a9">0&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> ps -a
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">elif&lt;/span> [ &lt;span style="color:#40ffff">$1&lt;/span> == &lt;span style="color:#ed9d13">&amp;#34;up&amp;#34;&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> up -d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">elif&lt;/span> [ &lt;span style="color:#40ffff">$1&lt;/span> == &lt;span style="color:#ed9d13">&amp;#34;php&amp;#34;&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [ &lt;span style="color:#40ffff">$#&lt;/span> -gt &lt;span style="color:#3677a9">1&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> &lt;span style="color:#24909d">exec&lt;/span> php su app -c &lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#ed9d13">${&lt;/span>*:&lt;span style="color:#40ffff">2&lt;/span>&lt;span style="color:#ed9d13">}&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> &lt;span style="color:#24909d">exec&lt;/span> php su app
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">elif&lt;/span> [ &lt;span style="color:#40ffff">$1&lt;/span> == &lt;span style="color:#ed9d13">&amp;#34;c&amp;#34;&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> &lt;span style="color:#24909d">exec&lt;/span> php su app -c &lt;span style="color:#ed9d13">&amp;#34;composer &lt;/span>&lt;span style="color:#ed9d13">${&lt;/span>*:&lt;span style="color:#40ffff">2&lt;/span>&lt;span style="color:#ed9d13">}&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">elif&lt;/span> [ &lt;span style="color:#40ffff">$1&lt;/span> == &lt;span style="color:#ed9d13">&amp;#34;ci&amp;#34;&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> &lt;span style="color:#24909d">exec&lt;/span> php su app -c &lt;span style="color:#ed9d13">&amp;#39;composer install&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">elif&lt;/span> [ &lt;span style="color:#40ffff">$1&lt;/span> == &lt;span style="color:#ed9d13">&amp;#34;recreate&amp;#34;&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> up -d --force-recreate &lt;span style="color:#ed9d13">${&lt;/span>*:&lt;span style="color:#40ffff">2&lt;/span>&lt;span style="color:#ed9d13">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">elif&lt;/span> [ &lt;span style="color:#40ffff">$1&lt;/span> == &lt;span style="color:#ed9d13">&amp;#34;build&amp;#34;&lt;/span> ]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> up -d --force-recreate --build &lt;span style="color:#ed9d13">${&lt;/span>*:&lt;span style="color:#40ffff">2&lt;/span>&lt;span style="color:#ed9d13">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span> &lt;span style="color:#40ffff">$DC&lt;/span> &lt;span style="color:#40ffff">$*&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">32&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Give execute permission with &lt;code>chmod +x ./dc&lt;/code>&lt;/p>
&lt;p>And now you can run:&lt;/p>
&lt;ul>
&lt;li>&lt;code>./dc&lt;/code> - to show all containers with status&lt;/li>
&lt;li>&lt;code>./dc up&lt;/code> - to start in detached mode&lt;/li>
&lt;li>&lt;code>./dc ci&lt;/code> - to run composer install in the php container as user app&lt;/li>
&lt;li>&lt;code>./dc c require spatie/image&lt;/code> - to run any composer command inside php container&lt;/li>
&lt;li>&lt;code>./dc php&lt;/code> - interactive exec inside php container&lt;/li>
&lt;li>&lt;code>./dc php ls -alh&lt;/code> - run any command inside php container&lt;/li>
&lt;li>&lt;code>./dc recreate&lt;/code> - applies any modifications to docker-compose.yml&lt;/li>
&lt;li>&lt;code>./dc recreate php&lt;/code> - applies modifications to compose, only for php container&lt;/li>
&lt;li>&lt;code>./dc build&lt;/code> - if you have a custom dockerfile, does run dc up with a fresh build.&lt;/li>
&lt;li>&lt;code>./dc logs -n 10 -f php&lt;/code> - any other docker-compose command works as expected.&lt;/li>
&lt;/ul>
- https://telteu.ro/posts/docker-compose-helper-script/ - Andrei Telteu 2024</description></item><item><title>Incremental file and MySQL backup</title><link>https://telteu.ro/posts/incremental-backup-files-and-mysql/</link><pubDate>Mon, 18 Nov 2024 00:09:52 +0200</pubDate><guid>https://telteu.ro/posts/incremental-backup-files-and-mysql/</guid><description>Andrei Telteu https://telteu.ro/posts/incremental-backup-files-and-mysql/ -&lt;h2 id="1-install">1. Install&lt;/h2>
&lt;p>Install autorestic:
&lt;a href="https://autorestic.vercel.app/installation" target="_blank" rel="noopener">https://autorestic.vercel.app/installation&lt;/a>
&lt;/p>
&lt;p>Let&amp;rsquo;s use &lt;code>/root/backup&lt;/code> to store our env file and autorestic config, make a &lt;code>data&lt;/code> folder inside to store the actual backups inside, and a temporary &lt;code>database&lt;/code> folder for MySQL dumps.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>mkdir /root/backup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span>mkdir /root/backup/data
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span>mkdir /root/backup/database
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">4&lt;/span>&lt;span>&lt;span style="color:#24909d">cd&lt;/span> /root/backup
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="2-environment">2. Environment&lt;/h2>
&lt;p>Create the environment file &lt;code>nano .autorestic.env&lt;/code> and fill the access data to the database:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-env" data-lang="env">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>&lt;span style="color:#40ffff">AUTORESTIC_LOCAL_RESTIC_PASSWORD&lt;/span>=
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span>&lt;span style="color:#40ffff">AUTORESTIC_PROD_DB_MYSQL_HOST&lt;/span>=localhost
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">4&lt;/span>&lt;span>&lt;span style="color:#40ffff">AUTORESTIC_PROD_DB_MYSQL_PORT&lt;/span>=&lt;span style="color:#3677a9">3306&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">5&lt;/span>&lt;span>&lt;span style="color:#40ffff">AUTORESTIC_PROD_DB_MYSQL_DATABASE&lt;/span>=
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">6&lt;/span>&lt;span>&lt;span style="color:#40ffff">AUTORESTIC_PROD_DB_MYSQL_USER&lt;/span>=
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">7&lt;/span>&lt;span>&lt;span style="color:#40ffff">AUTORESTIC_PROD_DB_MYSQL_PASS&lt;/span>=
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Generate a unique key / password in &lt;code>AUTORESTIC_LOCAL_RESTIC_PASSWORD&lt;/code>. This is used to encrypt and decrypt all backups. Also please save backup this key in a different location as well (password manager or something).&lt;/p>
&lt;h2 id="3-mysql-backup">3. MySQL Backup&lt;/h2>
&lt;p>Make a bash script for MySQL backup: &lt;code>nano backup-db-hook.sh&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#cd2828;font-weight:bold">#!/usr/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#cd2828;font-weight:bold">&lt;/span>&lt;span style="color:#40ffff">BACKUP_PATH&lt;/span>=./database
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>mkdir &lt;span style="color:#40ffff">$BACKUP_PATH&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#24909d">export&lt;/span> &lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>cat .autorestic.env | xargs&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#40ffff">MYSQL&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>which mysql&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#40ffff">MYSQLDUMP&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>which mysqldump&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#40ffff">GZIP&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>which gzip&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>&lt;span style="color:#40ffff">MYSQL_PERMS&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34; --protocol tcp &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>&lt;span style="color:#40ffff">MYSQL_PERMS&lt;/span>+=&lt;span style="color:#ed9d13">&amp;#34; -h &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>&lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#40ffff">$AUTORESTIC_PROD_DB_MYSQL_HOST&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13"> &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>&lt;span style="color:#40ffff">MYSQL_PERMS&lt;/span>+=&lt;span style="color:#ed9d13">&amp;#34; -P &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>&lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#40ffff">$AUTORESTIC_PROD_DB_MYSQL_PORT&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13"> &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>&lt;span style="color:#40ffff">MYSQL_PERMS&lt;/span>+=&lt;span style="color:#ed9d13">&amp;#34; -u &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>&lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#40ffff">$AUTORESTIC_PROD_DB_MYSQL_USER&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13"> &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>&lt;span style="color:#40ffff">DB&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#40ffff">$AUTORESTIC_PROD_DB_MYSQL_DATABASE&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span>&lt;span style="color:#24909d">export&lt;/span> &lt;span style="color:#40ffff">MYSQL_PWD&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#40ffff">$AUTORESTIC_PROD_DB_MYSQL_PASS&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span>&lt;span style="color:#40ffff">DUMP_OPTIONS&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;--single-transaction --no-tablespaces&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>&lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>date +&lt;span style="color:#ed9d13">&amp;#34;%d-%m-%Y %H:%M:%S&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13"> Backing up &lt;/span>&lt;span style="color:#40ffff">$DB&lt;/span>&lt;span style="color:#ed9d13"> to &lt;/span>&lt;span style="color:#40ffff">$BACKUP_PATH&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#40ffff">TABLES&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>&lt;span style="color:#40ffff">$MYSQL&lt;/span> &lt;span style="color:#40ffff">$MYSQL_PERMS&lt;/span> &lt;span style="color:#40ffff">$DB&lt;/span> -Bse &lt;span style="color:#ed9d13">&amp;#39;SHOW TABLES FROM &amp;#39;&lt;/span>&lt;span style="color:#40ffff">$DB&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">for&lt;/span> TABLE in &lt;span style="color:#40ffff">$TABLES&lt;/span> ; &lt;span style="color:#6ab825;font-weight:bold">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span> &lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>date +&lt;span style="color:#ed9d13">&amp;#34;%d-%m-%Y %H:%M:%S&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13"> Backing up &lt;/span>&lt;span style="color:#40ffff">$TABLE&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span> &lt;span style="color:#40ffff">FILE&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#40ffff">$BACKUP_PATH&lt;/span>&lt;span style="color:#ed9d13">/&lt;/span>&lt;span style="color:#ed9d13">${&lt;/span>&lt;span style="color:#40ffff">TABLE&lt;/span>&lt;span style="color:#ed9d13">}&lt;/span>&lt;span style="color:#ed9d13">.sql.gz&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span> &lt;span style="color:#40ffff">$MYSQLDUMP&lt;/span> &lt;span style="color:#40ffff">$MYSQL_PERMS&lt;/span> &lt;span style="color:#40ffff">$DUMP_OPTIONS&lt;/span> &lt;span style="color:#40ffff">$DB&lt;/span> &lt;span style="color:#40ffff">$TABLE&lt;/span> | &lt;span style="color:#40ffff">$GZIP&lt;/span> -9 &amp;gt; &lt;span style="color:#40ffff">$FILE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">done&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span>&lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">$(&lt;/span>date +&lt;span style="color:#ed9d13">&amp;#34;%d-%m-%Y %H:%M:%S&amp;#34;&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">)&lt;/span>&lt;span style="color:#ed9d13"> ...done!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(credits to
&lt;a href="https://gist.github.com/jeremyharris/3085738" target="_blank" rel="noopener">jeremyharris/backup.sh&lt;/a>
for separate db tables script)&lt;/p>
&lt;h2 id="4-config">4. Config&lt;/h2>
&lt;p>Make a config file: &lt;code>nano auto.yml&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yml" data-lang="yml">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">version&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">2&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">backends&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">local&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">type&lt;/span>:&lt;span style="color:#666"> &lt;/span>local&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">path&lt;/span>:&lt;span style="color:#666"> &lt;/span>/root/backup/data&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># where you want to store all backups&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">global&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">forget&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">keep-daily&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">7&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">keep-weekly&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#3677a9">4&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span>&lt;span style="color:#666">&lt;/span>&lt;span style="color:#6ab825;font-weight:bold">locations&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">prod&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">from&lt;/span>:&lt;span style="color:#666"> &lt;/span>/var/www/html&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># where the website files are&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">to&lt;/span>:&lt;span style="color:#666"> &lt;/span>local&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">cron&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;0 1 * * *&amp;#39;&lt;/span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># at 01:00&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">forget&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;yes&amp;#34;&lt;/span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># or &amp;#34;prune&amp;#34;. Yes must be in quotes, otherwise it&amp;#39;s a boolean&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">options&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">backup&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">exclude&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- &lt;span style="color:#ed9d13">&amp;#39;vendor&amp;#39;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">prod-db&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">from&lt;/span>:&lt;span style="color:#666"> &lt;/span>/root/backup/database/&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">to&lt;/span>:&lt;span style="color:#666"> &lt;/span>local&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">cron&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#39;0 0 * * *&amp;#39;&lt;/span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#999;font-style:italic"># at 00:00&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">forget&lt;/span>:&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#ed9d13">&amp;#34;yes&amp;#34;&lt;/span>&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">hooks&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>&lt;span style="color:#6ab825;font-weight:bold">before&lt;/span>:&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span>&lt;span style="color:#666"> &lt;/span>- bash backup-db-hook.sh&lt;span style="color:#666">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note: The backend name must match with the env restic password name: (like &lt;code>&lt;b>EXAMPLE&lt;/b>&lt;/code>)
&lt;br />AUTORESTIC_&lt;code>&lt;b>EXAMPLE&lt;/b>&lt;/code>_RESTIC_PASSWORD=
&lt;br />backends:
&lt;br />  &lt;code>&lt;b>example&lt;/b>&lt;/code>:
&lt;br />    type: local&lt;/p>
&lt;/blockquote>
&lt;h2 id="5-initialize-repository">5. Initialize repository&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>autorestic check
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will check your config and initialize a new repository in the backup destination folder or remote location.&lt;/p>
&lt;h2 id="6-cron-job">6. Cron Job&lt;/h2>
&lt;p>Add the cron job. autorestic recommends every 5 minutes.&lt;/p>
&lt;p>&lt;code>crontab -e&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>*/5 * * * * &lt;span style="color:#24909d">cd&lt;/span> /root/backup; /usr/local/bin/autorestic -c /root/backup/auto.yml --ci cron --lean
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="notes">Notes:&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Backup your key&lt;/strong> (env RESTIC_PASSWORD) somewhere else (like a password manager). If you lose it, &lt;strong>your backups are useless&lt;/strong>.&lt;/li>
&lt;li>Use &lt;code>autorestic exec -av snapshots&lt;/code> while in the &lt;code>/root/backup&lt;/code> folder to see the list of backups.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">1&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">## list of backups&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">2&lt;/span>&lt;span>autorestic -c auto.yml &lt;span style="color:#24909d">exec&lt;/span> -av snapshots
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">3&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">4&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">## choose one snapshot id, then list all the files within it&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">5&lt;/span>&lt;span>autorestic -c auto.yml &lt;span style="color:#24909d">exec&lt;/span> -av -- ls --long 041c88da
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">6&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">7&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">## now you can choose to restore only one file for example, in the relative folder ./restore/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">8&lt;/span>&lt;span>autorestic -c auto.yml &lt;span style="color:#24909d">exec&lt;/span> -av -- restore --target=./restore/ --include=/root/backup/database/example.sql.gz 041c88da
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>- https://telteu.ro/posts/incremental-backup-files-and-mysql/ - Andrei Telteu 2024</description></item><item><title>MySQL dynamic max_connections setting</title><link>https://telteu.ro/posts/mysql-dynamic-max-connections/</link><pubDate>Mon, 18 Nov 2024 00:08:54 +0200</pubDate><guid>https://telteu.ro/posts/mysql-dynamic-max-connections/</guid><description>Andrei Telteu https://telteu.ro/posts/mysql-dynamic-max-connections/ -&lt;p>Put the following script in a .sh file, for example in &lt;code>/root/watch-mysql.sh&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#cd2828;font-weight:bold">#!/usr/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#cd2828;font-weight:bold">&lt;/span>&lt;span style="color:#24909d">trap&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;exit&amp;#34;&lt;/span> &lt;span style="color:#3677a9">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#40ffff">MAXCONN&lt;/span>=&lt;span style="color:#3677a9">1000&lt;/span> &lt;span style="color:#999;font-style:italic"># set this to whatever base max_connections you have defined in your my.conf setting&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">while&lt;/span> true; &lt;span style="color:#6ab825;font-weight:bold">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">#mysql -e &amp;#34;SHOW VARIABLES LIKE &amp;#39;max_connections&amp;#39;;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span> &lt;span style="color:#40ffff">THREADS&lt;/span>=&lt;span style="color:#ed9d13">`&lt;/span>mysqladmin status | awk &lt;span style="color:#ed9d13">&amp;#39;{print $4}&amp;#39;&lt;/span>&lt;span style="color:#ed9d13">`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span> &lt;span style="color:#40ffff">THREADSINT&lt;/span>=&lt;span style="color:#ed9d13">`&lt;/span>&lt;span style="color:#24909d">echo&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;&lt;/span>&lt;span style="color:#40ffff">$THREADS&lt;/span>&lt;span style="color:#ed9d13">&amp;#34;&lt;/span> | bc&lt;span style="color:#ed9d13">`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">#echo &amp;#34;Load is: $THREADS&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span> &lt;span style="color:#40ffff">NEWMAX&lt;/span>=&lt;span style="color:#40ffff">$MAXCONN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [[ &lt;span style="color:#40ffff">$THREADSINT&lt;/span> -ge &lt;span style="color:#3677a9">1&lt;/span> ]]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span> &lt;span style="color:#40ffff">NEWMAX&lt;/span>=&lt;span style="color:#3677a9">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [[ &lt;span style="color:#40ffff">$THREADSINT&lt;/span> -ge &lt;span style="color:#3677a9">600&lt;/span> ]]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span> &lt;span style="color:#40ffff">NEWMAX&lt;/span>=&lt;span style="color:#3677a9">2000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [[ &lt;span style="color:#40ffff">$THREADSINT&lt;/span> -ge &lt;span style="color:#3677a9">1400&lt;/span> ]]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span> &lt;span style="color:#40ffff">NEWMAX&lt;/span>=&lt;span style="color:#3677a9">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [[ &lt;span style="color:#40ffff">$THREADSINT&lt;/span> -ge &lt;span style="color:#3677a9">2400&lt;/span> ]]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span> &lt;span style="color:#40ffff">NEWMAX&lt;/span>=&lt;span style="color:#3677a9">4000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [[ &lt;span style="color:#40ffff">$THREADSINT&lt;/span> -ge &lt;span style="color:#3677a9">3400&lt;/span> ]]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span> &lt;span style="color:#40ffff">NEWMAX&lt;/span>=&lt;span style="color:#3677a9">5000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">if&lt;/span> [[ &lt;span style="color:#40ffff">$NEWMAX&lt;/span> -ne &lt;span style="color:#40ffff">$MAXCONN&lt;/span> ]]; &lt;span style="color:#6ab825;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span> mysql -e &lt;span style="color:#ed9d13">&amp;#34;set global max_connections = &lt;/span>&lt;span style="color:#40ffff">$NEWMAX&lt;/span>&lt;span style="color:#ed9d13">;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">#echo &amp;#34;increased: $NEWMAX&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span> &lt;span style="color:#40ffff">MAXCONN&lt;/span>=&lt;span style="color:#40ffff">$NEWMAX&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span> sleep &lt;span style="color:#3677a9">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">32&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If &lt;code>mysqladmin status&lt;/code> gives error &amp;ldquo;connect to server at &amp;rsquo;localhost&amp;rsquo; failed&amp;rdquo;, make sure you have your credentials stored in &lt;code>~/.my.cnf&lt;/code>&lt;/p>
&lt;p>I have a separate mysql server, runing PerconaDB inside docker, so in my case my &lt;code>~/.my.cnf&lt;/code> looks like this:&lt;/p>
&lt;pre tabindex="0">&lt;code>[client]
protocol=tcp
port=3306
user=root
password=&amp;#34;secret&amp;#34;
&lt;/code>&lt;/pre>&lt;hr>
&lt;p>You can run this script on startup by creating a
&lt;a href="https://linuxconfig.org/how-to-run-script-on-startup-on-ubuntu-20-04-focal-fossa-server-desktop" target="_blank" rel="noopener">systemd service&lt;/a>
or by using
&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-manage-supervisor-on-ubuntu-and-debian-vps" target="_blank" rel="noopener">supervisor&lt;/a>
.&lt;/p>
&lt;hr>
&lt;p>An easier setup is by runing a cron job every minute. If you do a while loop in a cron job, you will end up with unlimited proceses spawned and we don&amp;rsquo;t want that. Instead we will replace while with a for loop:&lt;/p>
&lt;pre tabindex="0">&lt;code># replace `while true; do` with
for i in {1..20}; do
&lt;/code>&lt;/pre>&lt;p>For loop for 20 iterations because each loop sleeps for 3 seconds. So &lt;code>20 * 3 = 60&lt;/code> seconds assuming our code does not take too long to execute.&lt;/p>
&lt;p>Now run command &lt;code>crontab -e&lt;/code> and add a cron job for this:&lt;/p>
&lt;pre tabindex="0">&lt;code>* * * * * bash /root/watch-mysql.sh
&lt;/code>&lt;/pre>- https://telteu.ro/posts/mysql-dynamic-max-connections/ - Andrei Telteu 2024</description></item><item><title>Solid JS full year calendar</title><link>https://telteu.ro/posts/solidjs-full-year-calendar/</link><pubDate>Mon, 18 Nov 2024 00:07:59 +0200</pubDate><guid>https://telteu.ro/posts/solidjs-full-year-calendar/</guid><description>Andrei Telteu https://telteu.ro/posts/solidjs-full-year-calendar/ -&lt;div class="highlight">&lt;pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 1&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> { Component, For } &lt;span style="color:#6ab825;font-weight:bold">from&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;solid-js&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 2&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">import&lt;/span> moment &lt;span style="color:#6ab825;font-weight:bold">from&lt;/span> &lt;span style="color:#ed9d13">&amp;#34;moment&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 3&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">// import &amp;#34;moment/dist/locale/ro&amp;#34;; // if you need to change the locale
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 4&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">// moment.locale(&amp;#34;ro&amp;#34;);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 5&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 6&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">const&lt;/span> FullCalendar: &lt;span style="color:#6ab825;font-weight:bold">Component&lt;/span> = () =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 7&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">const&lt;/span> weekdays = moment.weekdaysMin();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 8&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">const&lt;/span> months = moment.months();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868"> 9&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">const&lt;/span> fullYear = &lt;span style="color:#24909d">Object&lt;/span>.fromEntries(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">10&lt;/span>&lt;span> months.map((monthName, monthIndex) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">11&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">12&lt;/span>&lt;span> monthName,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">13&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">new&lt;/span> &lt;span style="color:#24909d">Array&lt;/span>(&lt;span style="color:#3677a9">6&lt;/span>).fill(&lt;span style="color:#3677a9">1&lt;/span>).map((i, rowIndex) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">14&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> weekdays.map((dayName, colIndex) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">15&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">const&lt;/span> day = moment()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">16&lt;/span>&lt;span> &lt;span style="color:#999;font-style:italic">// .year(2024) // if you need to change the year
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">17&lt;/span>&lt;span>&lt;span style="color:#999;font-style:italic">&lt;/span> .month(monthIndex)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">18&lt;/span>&lt;span> .date(rowIndex * &lt;span style="color:#3677a9">7&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">19&lt;/span>&lt;span> .weekday(colIndex);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">20&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> day.month() == monthIndex ? day.format(&lt;span style="color:#ed9d13">&amp;#34;D&amp;#34;&lt;/span>) : &lt;span style="color:#ed9d13">&amp;#34;&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">21&lt;/span>&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">22&lt;/span>&lt;span> }),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">23&lt;/span>&lt;span> ];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">24&lt;/span>&lt;span> })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">25&lt;/span>&lt;span> );
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">26&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">27&lt;/span>&lt;span> &lt;span style="color:#6ab825;font-weight:bold">return&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">28&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-container&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">29&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span> &lt;span style="color:#bbb">each&lt;/span>={&lt;span style="color:#24909d">Object&lt;/span>.keys(fullYear)}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">30&lt;/span>&lt;span> {(monthName) =&amp;gt; (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">31&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-month&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">32&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-monthname&amp;#34;&lt;/span>&amp;gt;{monthName}&amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">33&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-weekdays&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">34&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span> &lt;span style="color:#bbb">each&lt;/span>={weekdays}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">35&lt;/span>&lt;span> {(weekDayName) =&amp;gt; (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">36&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-weekday solidcalendar-column&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">37&lt;/span>&lt;span> {weekDayName}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">38&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">39&lt;/span>&lt;span> )}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">40&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">41&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">42&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">43&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span> &lt;span style="color:#bbb">each&lt;/span>={fullYear[monthName]}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">44&lt;/span>&lt;span> {(days) =&amp;gt; (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">45&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-week&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">46&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span> &lt;span style="color:#bbb">each&lt;/span>={days}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">47&lt;/span>&lt;span> {(day) =&amp;gt; (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">48&lt;/span>&lt;span> &amp;lt;&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span> &lt;span style="color:#bbb">class&lt;/span>=&lt;span style="color:#ed9d13">&amp;#34;solidcalendar-weekday solidcalendar-column&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">49&lt;/span>&lt;span> {day}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">50&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">51&lt;/span>&lt;span> )}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">52&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">53&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">54&lt;/span>&lt;span> )}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">55&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">56&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">57&lt;/span>&lt;span> )}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">58&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">For&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">59&lt;/span>&lt;span> &amp;lt;/&lt;span style="color:#6ab825;font-weight:bold">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">60&lt;/span>&lt;span> );
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">61&lt;/span>&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">62&lt;/span>&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#686868">63&lt;/span>&lt;span>&lt;span style="color:#6ab825;font-weight:bold">export&lt;/span> &lt;span style="color:#6ab825;font-weight:bold">default&lt;/span> FullCalendar;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>- https://telteu.ro/posts/solidjs-full-year-calendar/ - Andrei Telteu 2024</description></item></channel></rss>