<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><id>https://vic.demuzere.be/articles/tags/linux/atom.xml</id><title>Vic Demuzere - Linux</title><link href="https://vic.demuzere.be/articles/tags/linux/atom.xml" rel="self" type="application/atom+xml" /><link href="https://vic.demuzere.be/articles/tags/linux/" rel="alternate" type="text/html" /><updated>2022-05-29T14:23:58+00:00</updated><author><name>Vic Demuzere</name></author><entry><id>https://vic.demuzere.be/articles/pwgen-not-secure-by-default/</id><title>Today I learned pwgen is not secure by default</title><link href="https://vic.demuzere.be/articles/pwgen-not-secure-by-default/" rel="alternate" /><updated>2024-11-11T18:19:13+00:00</updated><published>2022-05-29T14:23:58+00:00</published><content type="html"><![CDATA[<p>Command-line tool <a href="https://sourceforge.net/projects/pwgen/" title="Official pwgen pages on Sourceforge"><code>pwgen</code></a> is a well known tool to generate a list of passwords.
I use it almost daily: when creating new accounts on remote servers, or when I want to encrypt sensitive data with a temporary password to send to a customer.
Sometimes opening my terminal and typing <code>pwgen 30 1</code> is faster than getting to the generator in my password manager.<sup class="footnote-ref"><a href="#fn-manager" id="fnref-manager" data-footnote-ref>1</a></sup></p>
<p>I had noticed before that the passwords generated by <code>pwgen</code> seemed to contain patterns: repeating vowels is something that stands out.
I hadn't thought about it much, until I saw a colleague type <code>pwgen -s</code> at his terminal.</p>
<h2 id="what-is-this--s">What is this <code>-s</code>?<a href="#what-is-this--s" aria-label="Link to heading 'What is this -s?'" data-heading-content="What is this -s?" class="anchor"></a></h2>
<p>As with most unix-y tools, a quick glance at <a href="https://man.archlinux.org/man/pwgen.1" title="pwgen man page">the <em>man page</em></a> tells us everything we want to know.
The <code>-s</code> is shorthand for <code>--secure</code>:</p>
<blockquote>
<p>Generate completely random, hard-to-memorize passwords.
These should only be used for machine passwords, since otherwise it's almost guaranteed that users will simply write the password on a piece of paper taped to the monitor...</p>
</blockquote>
<p>As it turns out, <code>pwgen</code> actually doesn't generate secure passwords by default.
The passwords it generates are <em>designed to be easily memorized</em>.
That explains the patterns I noticed before!<sup class="footnote-ref"><a href="#fn-man" id="fnref-man" data-footnote-ref>2</a></sup></p>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-manager">
<p><a href="https://keepassxc.org/">KeepassXC</a> is a great password manager with local storage. <a href="#fnref-manager" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-man">
<p>I should have checked the man page right away: patterns are a red flag in cryptography. <a href="#fnref-man" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
</ol>
</section>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Today%20I%20learned%20pwgen%20is%20not%20secure%20by%20default">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/using-bash-variables-in-jq/</id><title>Using bash variables in jq</title><link href="https://vic.demuzere.be/articles/using-bash-variables-in-jq/" rel="alternate" /><updated>2024-11-11T18:21:44+00:00</updated><published>2021-02-10T20:01:03+00:00</published><content type="html"><![CDATA[<p>Due to the special characters used in json, the easiest way to use jq with inline scripts it by putting it between single quotes.
That <strong>makes it impossible to use bash variables inside your script</strong>.
Fortunately, jq has an <code>--arg</code> parameter to create a predefined variable from an external source.</p>
<p>You can use it to define a <code>$foo</code> variable with the contents of bash variable <code>$FOO</code>, for example:</p>
<pre><code>$ export FOO=&quot;bar&quot;
$ jq -n --arg foo &quot;$FOO&quot; '{foo: $foo}'
{
  &quot;foo&quot;: &quot;bar&quot;
}
</code></pre>
<p>You might notice the <code>-n</code> parameter: This tells <code>jq</code> to use <code>null</code> as input instead of reading json from stdin like it normally would.
I'm using it in all examples on this page as it makes them a bit shorter.
In real world usage, you probably won't need it.</p>
<p>As usual in bash scripts, you can also execute a command inline:</p>
<pre><code>$ jq -n --arg hostname &quot;$(hostname)&quot; '{foo: $hostname}'
{
  &quot;foo&quot;: &quot;cypher&quot;
}
</code></pre>
<p>Every variable created with <code>--arg</code> is <strong>treated as a string</strong>.
That might cause some unexpected behavior when you work with numbers, like when you attempt to add a number to an argument.
Comparisons between strings and numbers seem to work fine, but I wouldn't count on it (pun intended).</p>
<pre><code>$ echo '{&quot;a&quot;: 3.0}' | jq --arg foo 5 '$foo + .a'
jq: error (at &lt;stdin&gt;:1): string (&quot;5&quot;) and number (3) cannot be added
</code></pre>
<p>There are two ways to solve this: either convert the variable to a number with <code>tonumber</code> or use <code>--argjson</code> instead.
I prefer to use <code>tonumber</code> because that way I'm sure jq forces it to be a number.
As my argument may be the result of an earlier command, I may be using an error message as input instead of the expected numeric result.</p>
<pre><code>$ jq -n --arg foo 5 '($foo|tonumber) + 1'
6

$ jq -n --argjson foo 5 '$foo + 1'
6
</code></pre>
<h2 id="variables-from-files">Variables from files<a href="#variables-from-files" aria-label="Link to heading 'Variables from files'" data-heading-content="Variables from files" class="anchor"></a></h2>
<p>It's also possible to load variables from files.
With <code>--slurpfile</code> we can read a file containing json objects.
An array containing the separate objects is then made available as a predefined variable.
Note that even if your file contains only a single json object, as the variable is still an array, the <code>[0]</code> is required to access it.</p>
<pre><code>$ cat foo.json
{&quot;foo&quot;: &quot;bar&quot;}
{&quot;bar&quot;: &quot;foo&quot;}

$ jq -n --slurpfile foo foo.json '$foo[0].foo'
&quot;bar&quot;
</code></pre>
<p>A second option is <code>--rawfile</code>, creating a string variable with the exact contents of the file.
Note that as jq outputs json, reading and printing the file from the previous example results an escaped string.</p>
<pre><code>$ jq -n --rawfile foo foo.json '$foo'
&quot;{\&quot;foo\&quot;: \&quot;bar\&quot;}\n{\&quot;bar\&quot;: \&quot;foo\&quot;}\n&quot;
</code></pre>
<p>That's it!</p>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Using%20bash%20variables%20in%20jq">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/openssl-pfx-certificates/</id><title>Converting PFX certificates on Linux</title><link href="https://vic.demuzere.be/articles/openssl-pfx-certificates/" rel="alternate" /><updated>2023-11-28T19:55:32+00:00</updated><published>2020-04-15T16:19:47+00:00</published><content type="html"><![CDATA[<p>While most certificate vendors provide certificates in both PFX format and PEM,
most customers seem to send me their certificate in PFX format. Maybe because that way the
private key is usually encrypted, or maybe they're used to that format for their Windows machines.</p>
<h2 id="converting-using-openssl">Converting using OpenSSL<a href="#converting-using-openssl" aria-label="Link to heading 'Converting using OpenSSL'" data-heading-content="Converting using OpenSSL" class="anchor"></a></h2>
<p>The <code>openssl</code> command makes it easy to convert PFX files.
It may ask you for the password if the private key was encrypted.</p>
<p>Export only the private key to a file named <code>key.pem</code>:</p>
<pre><code>openssl pkcs12 -in cert.pfx -nocerts -out key.pem -nodes
</code></pre>
<p>Export only the public certificates to a file named <code>cert.pem</code>:</p>
<pre><code>openssl pkcs12 -in cert.pfx -nokeys -out cert.pem
</code></pre>
<p>Export both public and private keys to <code>bundle.pem</code>:</p>
<pre><code>openssl pkcs12 -in cert.pfx -out bundle.pem -nodes
</code></pre>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Converting%20PFX%20certificates%20on%20Linux">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/easy-ssh-connections-combell-shared-hosting/</id><title>Easy SSH connections to Combell shared hosting</title><link href="https://vic.demuzere.be/articles/easy-ssh-connections-combell-shared-hosting/" rel="alternate" /><updated>2023-11-28T19:55:32+00:00</updated><published>2019-12-16T12:13:30+00:00</published><content type="html"><![CDATA[<p>When trying to connect over SSH to your <a href="https://www.combell.com/en/hosting/web-hosting" title="Combell shared hosting">Combell shared hosting</a> account, the control panel explains how to connect using one of these two options:</p>
<ul>
<li><code>ssh yoursitebe@ssh.yoursite.be</code></li>
<li><code>ssh yoursitebe@ssh123.webhosting.be</code></li>
</ul>
<p>The first one <strong>may not work</strong> if your DNS records are not correct, the second one always works but is hard to remember.
With just a small change to our local SSH config, we can use a third option: <strong>simply connect to your domain name</strong>!</p>
<ul>
<li><code>ssh yoursite.be</code></li>
</ul>
<p>For this to work we have to tell <code>ssh</code> what to do with <code>yoursite.be</code>.</p>
<h2 id="the-local-ssh-config-file">The local SSH config file<a href="#the-local-ssh-config-file" aria-label="Link to heading 'The local SSH config file'" data-heading-content="The local SSH config file" class="anchor"></a></h2>
<p>On computers running Linux and macOS, the configuration file can be found at:</p>
<pre><code>~/.ssh/config
</code></pre>
<p>The file (or the <code>.ssh</code> directory) may not exist yet, you can create it manually.</p>
<p>Inside the file you can specify <code>Host</code> blocks to tell the SSH client what to do with certain hostnames.
We'll use our domain name as that's the natural address to connect to when we want to update our website.</p>
<pre><code>Host yoursite.be
	HostName ssh123.webhosting.be
	User yoursitebe

Host othersite.com
	HostName ssh472.webhosting.be
	User othersitecom
</code></pre>
<p>The correct values for the <code>HostName</code> and <code>User</code> parameters can be found after logging in to the <a href="https://my.combell.com" title="Combell control panel">My Combell control panel</a>.
Navigate to the correct web hosting account and click the <strong>SSH</strong> menu option on the left.
You'll see the <em>SSH host</em> and <em>SSH user name</em> listed there.</p>
<p>After saving the file, you can connect right away:</p>
<pre><code>ssh yoursite.be
Last login: Mon Dec 16 14:28:14 2019 from 178-221-32-24.access.telenet.be
yoursitebe@com-linssh123:~#
</code></pre>
<p>This also works when using <code>scp</code> or <code>rsync</code> to transfer files!</p>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Easy%20SSH%20connections%20to%20Combell%20shared%20hosting">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/nginx-outdated-content-being-served/</id><title>Outdated files being served by nginx</title><link href="https://vic.demuzere.be/articles/nginx-outdated-content-being-served/" rel="alternate" /><updated>2023-11-28T19:55:32+00:00</updated><published>2019-12-05T15:35:00+00:00</published><content type="html"><![CDATA[<p>While updating one of my websites I noticed that a CSS file wasn't being updated.</p>
<p>As I'm using Cloudflare to cache my website my first guess was that the cache on their side wasn't being cleared.
Pushed the clear cache button multiple times without any effect. It's clearly broken!
A direct request to my webserver cleared any blame on Cloudflare though: my server was <strong>replying with an old version</strong> of my CSS file.</p>
<p>Then it must be rsync! I'm using rsync to push the new versions of my website from my development machine to the server.
A few retries later the funny looking webpages suggested the CSS was still wrong.
Checking the file on my server confirmed that <strong>rsync had actually replaced the CSS</strong>, retrying the upload was useless.</p>
<p>Why was nginx still serving the old CSS? Turns out it was my configuration.</p>
<h2 id="sendfile">Sendfile<a href="#sendfile" aria-label="Link to heading 'Sendfile'" data-heading-content="Sendfile" class="anchor"></a></h2>
<p>As recommended by most optimization guides my nginx configuration allows using sendfile.
This option is especially useful for static websites like mine, as every single page can be served right from the filesystem.</p>
<pre><code>http {
  sendfile on;
  tcp_nopush on;
}
</code></pre>
<p>But what does it do exactly?</p>
<p>The nginx documentation <a href="https://nginx.org/en/docs/http/ngx_http_core_module.html#sendfile" title="documentation on the sendfile nginx configuration option">explains the <code>sendfile</code> option</a> as:</p>
<blockquote>
<p>Enables or disables the use of sendfile().</p>
</blockquote>
<p>That's exactly what I would expect from a boolean option!
Sendfile is actually a Linux system call executed by nginx, for more information we have to resort to the man pages.</p>
<blockquote>
<p>sendfile() copies data between one file descriptor and another.
Because this copying is done within the kernel, sendfile() is more
efficient than the combination of read(2) and write(2), which would
require transferring data to and from user space.</p>
</blockquote>
<p>So basically nginx just asks the kernel to copy the contents of a file to the connection with the visitor's browser.
This makes serving static files a lot faster, as it eliminates the step where nginx copies the file into its own buffers. Yay!</p>
<h2 id="open-file-cache">Open file cache<a href="#open-file-cache" aria-label="Link to heading 'Open file cache'" data-heading-content="Open file cache" class="anchor"></a></h2>
<p>Another optimization I've been using is the <code>open_file_cache</code> options:</p>
<pre><code>http {
  open_file_cache max=1000 inactive=20s;
  open_file_cache_errors on;
  open_file_cache_min_uses 2;
  open_file_cache_valid 30s;
}
</code></pre>
<p>When we turn to the nginx documentation again, what we should know about <a href="https://nginx.org/en/docs/http/ngx_http_core_module.html#open_file_cache" title="documentation on the open_file_cache nginx configuration option">the open file cache</a> is that it contains information about files being served from the filesystem:</p>
<ul>
<li>open file descriptors, their sizes and modification times</li>
<li>information on existence of directories</li>
<li>file lookup errors</li>
</ul>
<p>This cache is quite useful as the modification time allows nginx to reply to <code>If-Modified-Since</code> requests without actually opening the file.
Another situation that happens quite frequently is a non-existing file being requested multiple times.
The best known example is the <code>favicon.ico</code> that most browsers request whenever you visit a website.
As nginx already knows that the file is not actually there, it can simply reply with a 404 response right away.</p>
<p>Great, huh?</p>
<p>Remember how <code>sendfile</code> copies data <em>from one file descriptor to another</em>?
If the file on disk was replaced (not just modified) then this causes nginx to <strong>keep sending data from the old file</strong> instead of the new one.
This can be very confusing if you also have a web cache (Varnish, or a service like Cloudflare for example) as you'll be blaming the cache first.</p>
<p>Looks like there is no way to clear the open file cache.
As I don't want to restart nginx every time I update my website I have modified my configuration to no longer cache files for 30s.</p>
<h2 id="rsync">Rsync<a href="#rsync" aria-label="Link to heading 'Rsync'" data-heading-content="Rsync" class="anchor"></a></h2>
<p>As an extra: rsync <a href="https://rsync.samba.org/how-rsync-works.html" title="rsync documentation">is the reason why my files were replaced</a>.</p>
<blockquote>
<p>After the temp-file has been completed, its ownership and permissions and modification time are set. It is then renamed to replace the basis file.</p>
</blockquote>
<p>This means the existing file is not modified. It is actually replaced by a new file, to make sure we don't end up with only half of the contents in case transfer fails.</p>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Outdated%20files%20being%20served%20by%20nginx">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/combining-traditional-configuration-management-with-docker/</id><title>Combining traditional configuration management with Docker</title><link href="https://vic.demuzere.be/articles/combining-traditional-configuration-management-with-docker/" rel="alternate" /><updated>2023-11-28T19:55:32+00:00</updated><published>2018-10-15T18:23:00+00:00</published><content type="html"><![CDATA[<p>Configuration management systems like Ansible, Chef, Salt and Puppet are the <em>traditional</em> and proven way to automate server management.
Using a tool like one of these has a lot of benefits over manual configuration: Setting up a new server (for new projects or to replace a broken server) can be performed faster and more accurately than we could do manually.
It also makes sure that servers and individual services are configured exactly the same when you're doing it multiple times.
No doubt about the benefits of configuration management systems.</p>
<h2 id="hello-docker">Hello Docker!<a href="#hello-docker" aria-label="Link to heading 'Hello Docker!'" data-heading-content="Hello Docker!" class="anchor"></a></h2>
<p>Then Docker came and brought a new way to manage services.
With the <strong>Dockerfile</strong> it introduced a standardized way to describe exactly what should be running inside a container.
While containers were nothing new, the easy to use of the Docker toolchain changed everything.</p>
<p>If you're just managing a few servers and are not planning to scale using Kubernetes or similar orchestration tools, <strong>using docker can make managing your services harder</strong>.
Keeping containers up to date means you have to manage another package manager and configuration depends on whatever the image maintainer decided to add to the image.
Having a bit more flexibility in the software you're running is awesome, though!
That's why I decided to <strong>combine services running inside Docker containers with traditional configuration management</strong>.</p>
<h2 id="hybrid-configuration">Hybrid configuration<a href="#hybrid-configuration" aria-label="Link to heading 'Hybrid configuration'" data-heading-content="Hybrid configuration" class="anchor"></a></h2>
<p>Since I want to use my existing Ansible code to manage nginx and its configuration, I need to be able to:</p>
<ul>
<li>Start, stop and reload my nginx service using systemd</li>
<li>Configure nginx in <code>/etc/nginx</code></li>
<li>View and cycle logs in <code>/var/log/nginx</code></li>
<li>Connect to local services outside the container (<code>php-fpm</code>, Go webservices, ..)</li>
<li>Publish websites with document roots in <code>/var/www</code></li>
</ul>
<p>But I also want features that I can't get on my standard debian system like TLS 1.3 and brotli compression.</p>
<h2 id="managing-a-containerized-nginx-service-with-systemd">Managing a containerized nginx service with systemd<a href="#managing-a-containerized-nginx-service-with-systemd" aria-label="Link to heading 'Managing a containerized nginx service with systemd'" data-heading-content="Managing a containerized nginx service with systemd" class="anchor"></a></h2>
<p>First step was to create an <a href="https://hub.docker.com/r/sorcix/nginx/">nginx docker image</a> with support for everything I want.
The systemd unit below takes care of downloading and starting the container on my server.
Volumes are mounted on every important path listed above to make sure I can configure everything as if the nginx service was installed using the default Debian package.</p>
<pre><code>[Unit]
Description=Nginx
After=docker.service
Requires=docker.service

[Service]
TimeoutStartSec=0
Restart=always
ExecStartPre=/usr/bin/docker pull sorcix/nginx:latest
ExecStart=/usr/bin/docker run --net=host --name nginx --rm -v /etc/nginx:/etc/nginx:ro -v /var/log/nginx:/var/log/nginx:rw -v /etc/ssl:/etc/ssl:ro -v /var/www:/var/www sorcix/nginx:latest
ExecReload=/usr/bin/docker exec nginx nginx -s reload
ExecStop=/usr/bin/docker exec nginx nginx -s quit

[Install]
WantedBy=multi-user.target
</code></pre>
<h3 id="networking--security">Networking &amp; security<a href="#networking--security" aria-label="Link to heading 'Networking &amp; security'" data-heading-content="Networking &amp; security" class="anchor"></a></h3>
<p>The <code>--net=host</code> part makes the container use host networking instead of the separate docker network that is usually created for containers.
Forwarding ports 80 and 443 is not required (which actually makes traffic handling a little faster) and we can connect to services running on the host.
Note that this also means that the additional security that containers usually provide is now missing.
That's fine with me as I'm using this as a drop in replacement for the default Debian nginx package which does not provide containerization at all.</p>
<h3 id="updates">Updates<a href="#updates" aria-label="Link to heading 'Updates'" data-heading-content="Updates" class="anchor"></a></h3>
<p>The <code>ExecStartPre</code> command downloads new versions of the <code>sorcix/nginx</code> container every time I restart nginx.
As I manage the container image myself this isn't really an issue, but you should disable this when using images created by others.</p>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Combining%20traditional%20configuration%20management%20with%20Docker">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/jumphosts-in-ssh-config/</id><title>Configuring OpenSSH to use a jumphost</title><link href="https://vic.demuzere.be/articles/jumphosts-in-ssh-config/" rel="alternate" /><updated>2026-05-13T17:25:03+00:00</updated><published>2018-05-17T19:00:00+00:00</published><content type="html"><![CDATA[<p>Let's say you have an important server <em>Bulbasaur</em>.
You may want to restrict access to the SSH server to a few IP addresses as an extra layer of protection.
We can then use a secure whitelisted server (jumphost or bastion) to relay our SSH connections:</p>
<pre><code>ssh -J charmeleon.mydomain.net bulbasaur.mydomain.net
</code></pre>
<p>As we're connecting to Bulbasaur a lot, we may want to tell OpenSSH that we're using charmeleon as a jumphost for bulbasaur:</p>
<pre><code># ~/.ssh/config

Host bulbasaur.mydomain.net
	ProxyJump charmeleon.mydomain.net
</code></pre>
<p>With this configuration in place, we can simply use <code>ssh bulbasaur.mydomain.net</code>. This also works for scp, rsync and everything else that uses your local SSH client.</p>
<h2 id="working-with-legacy">Working with legacy<a href="#working-with-legacy" aria-label="Link to heading 'Working with legacy'" data-heading-content="Working with legacy" class="anchor"></a></h2>
<p>On versions of OpenSSH before 7.3 the <code>ProxyJump</code> option is not available.
In that case you'll have to use an alternative configuration using the <code>ProxyCommand</code> option to specify the exact command OpenSSH has to execute to set up the tunnel.</p>
<pre><code>Host bulbasaur.mydomain.net
	ProxyCommand ssh charmeleon.mydomain.net -W %h:%p
</code></pre>
<h2 id="oops-wildcards">Oops: wildcards<a href="#oops-wildcards" aria-label="Link to heading 'Oops: wildcards'" data-heading-content="Oops: wildcards" class="anchor"></a></h2>
<p>Watch out when you're using wildcards in your ssh config:</p>
<pre><code>Host *.mydomain.net
	ProxyJump charmeleon.mydomain.net
</code></pre>
<p>Using <code>ssh server.mydomain.net</code> now causes a loop as the connection to the jumphost also matches the block and tries to use the jumphost.</p>
<p>An easy way to solve this is an alias for the jumphost:</p>
<pre><code>Host charmeleon
	HostName charmeleon.mydomain.net

Host *.mydomain.net
	ProxyJump charmeleon
</code></pre>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Configuring%20OpenSSH%20to%20use%20a%20jumphost">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/backups-restic-systemd/</id><title>Using Restic and systemd to backup a linux host</title><link href="https://vic.demuzere.be/articles/backups-restic-systemd/" rel="alternate" /><updated>2023-11-28T19:55:32+00:00</updated><published>2017-11-24T21:20:00+00:00</published><content type="html"><![CDATA[<p>Since moving away from Digital Ocean (and their snapshots) I've been looking for a good way to create backups for my servers.
I've recently stumbled upon the <a href="https://restic.github.io/" title="Restic">Restic</a> project and have been using it ever since.</p>
<ul>
<li>Restic is very <strong>simple to use</strong>. It's a cli-tool with a few easy to understand commands and has good documentation including examples.</li>
<li>You <strong>don't need a special backup service</strong>. Restic runs on the host being backed up, and is happy to store its backups on a simple file server or cloud service.</li>
<li>Security is important and the developers have written a <strong>decent <a href="https://restic.readthedocs.io/en/latest/100_references.html#threat-model" title="Restic threat model">threat model</a></strong>: trust only the host where restic runs, which makes sense as it contains the data anyway. The place where you store your backups is always considered insecure.</li>
</ul>
<h2 id="mounting-storage-space">Mounting storage space<a href="#mounting-storage-space" aria-label="Link to heading 'Mounting storage space'" data-heading-content="Mounting storage space" class="anchor"></a></h2>
<p><a href="https://www.transip.be/" title="TransIP">TransIP</a> is giving 1TB of free storage on their <a href="https://www.transip.be/stack/" title="TransIP Stack">Stack storage service</a>, which is more than enough for my backup needs.
The downside is that the only useful way to access it is a painfully slow webdav mount.
If you're backing up data that changes fast and need a consistent state, I would suggest choosing a different place to store your data.
For most of my servers I don't really care about backup speeds, though.</p>
<p>Mounting the volume using an entry in <code>/etc/fstab</code> would work, but as I want to specify dependencies later I opt to create a <em><a href="https://www.freedesktop.org/software/systemd/man/systemd.mount.html" title="systemd Mount Unit">Mount Unit</a></em> instead.
This is basically the systemd version of a single fstab entry.</p>
<pre><code># /etc/systemd/systemd/mnt-backups.mount
[Unit]
Description=Backup storage
After=network-online.target
Wants=network-online.target

[Mount]
Type=davfs
What=https://something.stackstorage.com/remote.php/webdav/
Where=/mnt/backups
Options=uid=root,gid=root,file_mode=644,dir_mode=755,nosuid,noexec,rw
TiemoutSec=15

[Install]
WantedBy=multi-user.target
</code></pre>
<p>If you're using webdav (using davfs2) like me, you'll also have to set your username and password in the secrets file <code>/etc/davfs2/secrets</code>.
Be sure to restrict the permissions on this file as it contains passwords.</p>
<pre><code>https://something.stackstorage.com/remote.php/webdav/ username password
</code></pre>
<p>We can now tell systemd to mount our volume:</p>
<pre><code>systemctl start mnt-backups.mount
</code></pre>
<p>And also set it to be mounted every time our machine boots:</p>
<pre><code>systemctl enable mnt-backups.mount
</code></pre>
<h2 id="initialize-the-repository">Initialize the repository<a href="#initialize-the-repository" aria-label="Link to heading 'Initialize the repository'" data-heading-content="Initialize the repository" class="anchor"></a></h2>
<p>Before our first backup we have to initialize a repository.
This creates the directory structure and configuration that restic will use to store our backups.
Note that, as restic does not trust our backup volume, any configuration stored there is also encrypted!</p>
<pre><code>restic init --repo /mnt/backups/myserver
</code></pre>
<p>Do not forget the password you enter during this step.
Every single file on the backup volume is encrypted and without the password your backups become useless.</p>
<h2 id="backup-service">Backup service<a href="#backup-service" aria-label="Link to heading 'Backup service'" data-heading-content="Backup service" class="anchor"></a></h2>
<p>The <em><a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html" title="systemd Service Unit">Service Unit</a></em> shown below describes a service that creates a single backup and stops.</p>
<pre><code># /etc/systemd/system/backup.service
[Unit]
Description=Backup
After=mnt-backups.mount
Wants=mnt-backups.mount

[Service]
Type=simple
Environment=RESTIC_PASSWORD=mysupers3cr3tpassw0rd!
Environment=RESTIC_REPOSITORY=/mnt/backups/myserver
ExecStart=/usr/local/bin/restic backup /home /srv/web
</code></pre>
<p>In the <code>[Unit]</code> section we specify that the mount we created earlier is a requirement for making backups (<code>Wants</code>).
The <code>After</code> setting is used to order the units when both are set to start when booting the system.
It's a bit redundant to specify that the <em>Service</em> should be after the <em>Mount</em> as we already specified a dependency, but it's a common thing to do.</p>
<p>Note that I only backup my <code>/home</code> and <code>/srv/web</code> folders as everything else can either be recreated or is managed by Ansible on my servers.
If you prefer to have a copy of your entire filesystem remember to change the path!</p>
<p>We can now create a new backup manually by running <code>systemctl start backup</code>.
This isn't really useful by itself as we could have run <code>restic backup</code> manually just as easy, with the exception that we don't have to type the password anymore.
Once we combine this with a systemd timer, things become interesting!</p>
<p>Remember that we set the backup volume to be mounted on boot? That isn't really required.
As we have specified a dependency on the volume, systemd will check if it's mounted before starting the backup service.
The free <a href="https://www.transip.be/stack/" title="TransIP Stack">Stack</a> volume I'm using is a bit wonky though, so I prefer to keep it mounted as that's a bit more stable.</p>
<h2 id="creating-backups-automatically">Creating backups automatically<a href="#creating-backups-automatically" aria-label="Link to heading 'Creating backups automatically'" data-heading-content="Creating backups automatically" class="anchor"></a></h2>
<p>Now that our backup works, it's time to have it create a backup automatically every night.
Creating a <em><a href="https://www.freedesktop.org/software/systemd/man/systemd.mount.html" title="systemd Timer Unit">Timer Unit</a></em> with the same name as the service we want to start does exactly that!</p>
<pre><code># /etc/systemd/system/backup.timer
[Unit]
Description=Backup daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
</code></pre>
<p>This simple timer is set to run daily at midnight.
Setting the <code>Persistent</code> attribute tells systemd that if our host was down at midnight, it has to run the backup as soon as it comes up again.
As servers are usually online 24/7 this doesn't really matter but it is a great setting for desktops and laptops.</p>
<p>Enable the timer using systemctl:</p>
<pre><code>systemctl enable backup.timer
</code></pre>
<p>Now enjoy having a fresh backup of your server every night!
Similar to the backup service, you can also create a service to <a href="https://restic.readthedocs.io/en/latest/060_forget.html" title="Remove old snapshots">remove your old snapshots</a>.
By default <a href="https://restic.github.io/" title="Restic">Restic</a> just keeps adding data and never removes anything, this may become a problem pretty fast if you're backup up a lot of data.</p>
<h2 id="restoring">Restoring<a href="#restoring" aria-label="Link to heading 'Restoring'" data-heading-content="Restoring" class="anchor"></a></h2>
<p>As with any backup system: remember to test restoring your backups regularly.
Restic gives us two great options in case we fuck up and need our data back:</p>
<ul>
<li><a href="https://restic.readthedocs.io/en/latest/050_restore.html#restoring-from-a-snapshot" title="Restore a snapshot using restic">Restore a complete snapshot</a> if you know to which point in time you need to return and if you need a copy of all your files.</li>
<li><a href="https://restic.readthedocs.io/en/latest/050_restore.html#restore-using-mount" title="Mount all your snapshots using restic">Mount your backup repository</a> as a fuse filesystem, allowing you to browse all your snapshots and the files within as if they're all just there on your server.</li>
</ul>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Using%20Restic%20and%20systemd%20to%20backup%20a%20linux%20host">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/using-systemd-user-units/</id><title>Managing services for non-root users with systemd</title><link href="https://vic.demuzere.be/articles/using-systemd-user-units/" rel="alternate" /><updated>2023-11-28T19:55:32+00:00</updated><published>2017-09-01T19:36:00+00:00</published><content type="html"><![CDATA[<p>Systemd is mainly used to manage services on modern linux distributions, but it also allows non-root users to manage services running under their own account.
This makes systemd a great alternative to services like supervisord as it is able to detect crashes and automatically restarts the service.</p>
<h2 id="configuring-a-user-unit">Configuring a user unit<a href="#configuring-a-user-unit" aria-label="Link to heading 'Configuring a user unit'" data-heading-content="Configuring a user unit" class="anchor"></a></h2>
<p>The directory structure that holds unit files is similar to the systemwide configuration, but is located in a user's home directory:</p>
<pre><code>$ mkdir -p ~/.config/systemd/user
</code></pre>
<p>In the <code>user</code> folder we can create service units with a <code>.service</code> extension. A unit is a ini-style file describing a service that has to be managed.</p>
<p>Let's say we have a <a href="https://laravel.com/docs/5.4/queues#running-the-queue-worker">Laravel PHP queue worker</a> that we want to be managed by systemd, called <code>worker.service</code>:</p>
<pre><code>[Unit]
Description=Laravel PHP queue worker

[Service]
ExecStart=/usr/bin/env php /path/to/my/project/artisan queue:work --sleep=3 --tries=3

[Install]
WantedBy=default.target
</code></pre>
<p>Run <code>$ systemctl --user daemon-reload</code> to make systemd recognize your changes.</p>
<p>We can now manage this service with systemd:</p>
<ul>
<li><code>$ systemctl --user start worker</code> starts the service</li>
<li><code>$ systemctl --user stop worker</code> stops the service</li>
<li><code>$ systemctl --user restart worker</code> restarts the workers</li>
<li><code>$ systemctl --user status worker</code> shows us the service status</li>
</ul>
<p>If we want this service to start automatically <em>when our user logs in</em>, we have to enable it:</p>
<ul>
<li><code>$ systemctl --user enable worker</code></li>
<li><code>$ systemctl --user disable worker</code></li>
</ul>
<h2 id="viewing-logs">Viewing logs<a href="#viewing-logs" aria-label="Link to heading 'Viewing logs'" data-heading-content="Viewing logs" class="anchor"></a></h2>
<p>Everything our PHP script writes to stdout and stderr will be recorded by journald. We can view the logs for this specific service:</p>
<pre><code>$ journalctl -u worker
</code></pre>
<p>On older versions of systemd (like the one shipped with Debian Jessie), you might need to use a flag specific to user units:</p>
<pre><code>$ journalctl --user-unit worker
</code></pre>
<h2 id="automatically-restarting-on-failure">Automatically restarting on failure<a href="#automatically-restarting-on-failure" aria-label="Link to heading 'Automatically restarting on failure'" data-heading-content="Automatically restarting on failure" class="anchor"></a></h2>
<p>Let's be honest: things go wrong. When our worker crashes we want to make sure it's started again. Fortunately, we can configure systemd to restart on failure:</p>
<p>Add the following to the <code>[Service]</code> section of the unit file:</p>
<pre><code>RestartSec=10s
Restart=on-failure
</code></pre>
<p>This makes systemd restart the service 10 seconds after it has stopped with a non-zero exit code. If the process exited cleanly, systemd considers the work as done and won't restart the service until you manually start it later.</p>
<h2 id="starting-user-services-at-boot">Starting user services at boot<a href="#starting-user-services-at-boot" aria-label="Link to heading 'Starting user services at boot'" data-heading-content="Starting user services at boot" class="anchor"></a></h2>
<p>By default, systemd starts <em>enabled</em> user units when the user logs in, and <strong>stops them once the user has logged out</strong>. This is great for desktop pcs where a user wants to run things while he's using the computer. On servers, however, we may want to run those units all the time.</p>
<pre><code># loginctl enable-linger USERNAME
</code></pre>
<p>You can check the status for each user by:</p>
<pre><code># loginctl user-status USERNAME
</code></pre>
<p>It should show that the user is lingering:</p>
<pre><code>vic (1000)
           Since: Fri 2017-09-01 21:54:29 CEST; 3s ago
           State: lingering
            Unit: user-1000.slice
</code></pre>
<p>When the user is not logged in and does not have lingering enabled, loginctl doesn't know about any user sessions so it will return an error:</p>
<pre><code>Failed to get user: No user 1000 known or logged in
</code></pre>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Managing%20services%20for%20non-root%20users%20with%20systemd">vic@demuzere.be</a>.</p></div>]]></content></entry><entry><id>https://vic.demuzere.be/articles/golang-makefile-crosscompile/</id><title>Cross compiling Go applications with Make</title><link href="https://vic.demuzere.be/articles/golang-makefile-crosscompile/" rel="alternate" /><updated>2024-11-11T18:06:57+00:00</updated><published>2016-06-06T21:47:00+00:00</published><content type="html"><![CDATA[<p>When a new version of one of my Go apps is ready, I usually want to build and package the binary for multiple platforms.
This can easily be done in a shell script, but Make brings a bonus: it can run multiple builds at the same time.</p>
<h2 id="makefile-101">Makefile 101<a href="#makefile-101" aria-label="Link to heading 'Makefile 101'" data-heading-content="Makefile 101" class="anchor"></a></h2>
<p>In case you've worked with make before, skip this section!
If not: let's see what a basic makefile looks like.</p>
<p>Make defines <strong>targets</strong>, these are things that need to be done.
Usually a target represents a file that has to be created.
Every target contains a list of commands that have to be executed, we call that the <strong>recipe</strong>.
Make will only execute the recipe if a file with the same name as the target does not exist.
If your target does not represent a file, it's a <em>phony target</em>.</p>
<pre><code>mytarget:
	echo Hello world.

space: mytarget foo
	echo &quot;I'm in space.&quot;

foo:
	echo I am run only once
	touch foo

.PHONY: mytarget space
</code></pre>
<p>The above makefile contains 3 targets: <code>mytarget</code>, <code>foo</code> and <code>space</code>.
The second target tells us that it needs both other targets, so when you call <code>make space</code>, make will also execute <code>mytarget</code> and <code>foo</code>.</p>
<p>At the bottom of the file we define a special .PHONY target: Here we simply tell make which targets are phony targets.
Those do not represent a file on disk.
As we usually don't compile separate Go files, most of our targets will be phony targets.</p>
<p>Let's see what this does: save the file as <code>Makefile</code> and run <code>make space</code> in the same directory:</p>
<pre><code>$ make space  
echo Hello world.
Hello world.
echo I am run only once
I am run only once
echo &quot;I'm in space.&quot;
I'm in space.
</code></pre>
<p>Notice that make always tells us what command it is executing.
You can hide a command by prefixing it with @.
As we'll be executing multiple targets concurrently, it may be useful to see which commands are running.</p>
<p>Run <code>make space</code> again.
You'll see that the <code>foo</code> target is not run anymore.
That's because we created a file named foo and <code>foo</code> is not a phony target.</p>
<h3 id="variables">Variables<a href="#variables" aria-label="Link to heading 'Variables'" data-heading-content="Variables" class="anchor"></a></h3>
<p>GNU Make has two types of variables.
When we assign to a variable with <code>:=</code> the contents is evaluated at the time the variable is declared.
If we use just <code>=</code> the contents is evaluated every time we use the variable.</p>
<pre><code>MYVAR := Hello there! I am currently in $(shell pwd)
PWD = $(shell pwd)
</code></pre>
<p>The <code>pwd</code> shell command will be executed every time we use variable <code>$(PWD)</code> in the makefile, while <code>$(MYVAR)</code> will always contain the same value.</p>
<h2 id="cross-compiling">Cross compiling<a href="#cross-compiling" aria-label="Link to heading 'Cross compiling'" data-heading-content="Cross compiling" class="anchor"></a></h2>
<p>Make supports running multiple targets at the same time.
This means that we need a separate target for every GOOS and GOARCH in order to take advantage of the concurrency.</p>
<p>A simple way to do this would be:</p>
<pre><code>linux:
	GOOS=linux GOARCH=amd64 go build ...

windows:
	GOOS=windows GOARCH=amd64 go build ...

release: windows linux

.PHONY release windows linux
</code></pre>
<p>This builds both linux and windows binaries when we call <code>make release</code>.
We can improve this Makefile by looping over the platforms and architectures we want to build:</p>
<pre><code>PLATFORMS := linux/amd64 windows/amd64

release: $(PLATFORMS)

$(PLATFORMS):
	echo Hello, I am $@

.PHONY release $(PLATFORMS)
</code></pre>
<p>What we do here is create a target that contains all possible platforms.
Every platform is a separate target, just like it was in the previous Makefile.
That also means that we have to add every platform to the phony list.
Luckily, we can do that using the same variable. Inside the recipe we can use the special <code>$@</code> that contains the name of the current target.</p>
<p>The next part is a bit harder, we need to separate OS and ARCH.
Remember that variables can be evaluated at runtime?
We'll use that feature to create an <code>$(os)</code> and <code>$(arch)</code> var.</p>
<pre><code>temp = $(subst /, ,$@)
os = $(word 1, $(temp))
arch = $(word 2, $(temp))
</code></pre>
<p>String manipulation functions in make are limited, so we have to be a bit creative here.
We'll use these variables inside the <code>$(PLATFORM)</code> target.
Remember that <code>$@</code> contains the name of the current target?
When we replace the slash in this string we can use the <code>word</code> function to get the first and last part.</p>
<p>Combined with our previous Makefile, this becomes:</p>
<pre><code>PLATFORMS := linux/amd64 windows/amd64

temp = $(subst /, ,$@)
os = $(word 1, $(temp))
arch = $(word 2, $(temp))

release: $(PLATFORMS)

$(PLATFORMS):
	GOOS=$(os) GOARCH=$(arch) go build -o '$(os)-$(arch)' mypackage

.PHONY release $(PLATFORMS)
</code></pre>
<p>Note that variables can only be set outside the recipe.
As the contents is only evaluated when we use them, it still contains the correct value.</p>
<h2 id="concurrency">Concurrency<a href="#concurrency" aria-label="Link to heading 'Concurrency'" data-heading-content="Concurrency" class="anchor"></a></h2>
<p>We now have a Makefile that creates binaries for the platforms we listed in the <code>$(PLATFORMS)</code> variable.
When we call <code>make release</code> it builds everything we asked, one by one.
The main reason to use make is the easy concurrency: simply call make with the <code>-j n</code> argument, where n is the number of simultaneous jobs.</p>
<div class="footer"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href="mailto:vic@demuzere.be?subject=RE%3A%20Cross%20compiling%20Go%20applications%20with%20Make">vic@demuzere.be</a>.</p></div>]]></content></entry></feed>