<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Bert&amp;apos;s blog</title>
    <description>This blog saw the light during the Christmas holidays when I grew tired of manually switching on the tree&amp;apos;s lights.</description>
    <link>https://www.emelis.net/</link>
    <atom:link href="https://www.emelis.net/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 17 May 2026 10:13:38 +0000</pubDate>
    <lastBuildDate>Sun, 17 May 2026 10:13:38 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Containerized Nginx reverse-proxy and Let&apos;s Encrypt certificates</title>
        <description>&lt;p&gt;When exposing services running on your home server to the Internet, you only allow encrypted connections. I’m exposing Home Assistant, Jellyfin and some other things via a containerized Nginx with HTTP3 and I use Let’s Encrypt to supply certificates.&lt;/p&gt;

&lt;p&gt;With this setup, you have an A+ rating at Qualys.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;whats-in-this-guide&quot;&gt;What’s in this guide?&lt;/h2&gt;

&lt;p&gt;When you follow this guide you will have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Nginx set up as a reverse proxy&lt;/li&gt;
  &lt;li&gt;Nginx running in a container&lt;/li&gt;
  &lt;li&gt;HTTP3 support in Nginx&lt;/li&gt;
  &lt;li&gt;TLS provided by Let’s Encrypt certificates&lt;/li&gt;
  &lt;li&gt;Certificates installed by containerized Certbot&lt;/li&gt;
  &lt;li&gt;Automatic renewal of certificates using a systemd timer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A container engine like Podman or Docker. I’m using Podman on an RHEL system (with SELinux enforced)&lt;/li&gt;
  &lt;li&gt;Podman-compose or docker-compose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Port forwarding and firewall management are out of the scope of this guide. For HTTP3 you will need to open port 80/TCP (only to redirect to port 443) and port 443 (UDP and TCP).&lt;/p&gt;

&lt;h2 id=&quot;http3-and-nginx&quot;&gt;HTTP3 and Nginx&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP/3&quot;&gt;HTTP3&lt;/a&gt; may be officially released as a standard, in Nginx it has not yet made it into the stable release.
Nginx does, however, have the code ready for those brave enough to try. And we sure are brave, aren’t we?&lt;/p&gt;

&lt;p&gt;F5, the company behind Nginx even provides a ready-to-use Dockerfile so you can build Nginx yourself. This also comes in handy if you want to add your own modules.&lt;/p&gt;

&lt;p&gt;The source of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Containerfile&lt;/code&gt; is found on the Nginx website: &lt;a href=&quot;https://www.nginx.com/blog/our-roadmap-quic-http-3-support-nginx/&quot;&gt;https://www.nginx.com/blog/our-roadmap-quic-http-3-support-nginx/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste the code from the blog entry and confirm it builds.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ podman build -t nginx-http3 .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;directory-structure-and-files&quot;&gt;Directory structure and files&lt;/h2&gt;

&lt;p&gt;Because I’m going to run an Nginx and Certbot container separately, I have to take care of the directory structure. I also want the Nginx logs to persist, outside of the container, so I can run log-parsing services like fail2ban.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ home - nginx
           |
           + container-compose.yml
           + Containerfile
           +- conf
           |    |
           |    + nginx.conf
           |    + http3.conf
           |    + letsencrypt-acme-challenge.conf
           |    +- conf.d
           |         |
           |         + sub.domain.tld.conf
           +- data
           |   |
           |   +- letsencrypt
           |   +- www
           +- log
               |
               +- letsencrypt
               +- nginx
                    |
                    + access.log
                    + error.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(directories have a dash before their name)&lt;/p&gt;

&lt;p&gt;The Nginx log files are already created. I noticed that Nginx sometimes has problems with creating the files on startup.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/nginx/container-compose.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;version: &quot;3.9&quot;
services:
  nginx-http3:
    build: ./
    container_name: nginx
    #restart: unless-stopped
    volumes:
      - ~/nginx/conf:/etc/nginx:Z,ro
      - ~/nginx/log:/var/log:z
      - ~/nginx/data/www:/srv:z,ro
      - ~/nginx/data/letsencrypt:/letsencrypt:z,ro
    network_mode: host
    #ports:
    #  - &quot;80:80&quot;
    #  - &quot;443:443/tcp&quot;
    #  - &quot;443:443/udp&quot;
    #networks:
    #  - nginx_backend

#networks:
#  nginx_backend:
#    name: nginx_backend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A few words of explanation here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Nginx container uses host networking mode. This is to have the real client’s IP address available for logging purposes. There is &lt;a href=&quot;https://github.com/containers/podman/pull/16141&quot;&gt;a new network driver&lt;/a&gt; coming to Podman but it hasn’t made it to the standard RHEL repos yet.&lt;/li&gt;
  &lt;li&gt;Because we use the host network, you cannot connect to a second Podman network. Backend services will have to expose their port on the post to be reachable. Note that their port should still be firewalled.&lt;/li&gt;
  &lt;li&gt;Volumes are mapped as we created them in our home directory. They all are read-only except the log directory. Don’t forget the SELinux flags!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/nginx/Containerfile&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FROM nginx AS build

WORKDIR /src
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y git gcc make autoconf libtool perl
RUN git clone -b v3.6.1 https://github.com/libressl-portable/portable.git libressl &amp;amp;&amp;amp; \
    cd libressl &amp;amp;&amp;amp; \
    ./autogen.sh &amp;amp;&amp;amp; \
    ./configure &amp;amp;&amp;amp; \
    make check &amp;amp;&amp;amp; \
    make install

RUN apt-get install -y mercurial libperl-dev libpcre3-dev zlib1g-dev libxslt1-dev libgd-ocaml-dev libgeoip-dev
RUN hg clone -b quic https://hg.nginx.org/nginx-quic &amp;amp;&amp;amp; \
    cd nginx-quic &amp;amp;&amp;amp; \
    auto/configure `nginx -V 2&amp;gt;&amp;amp;1 | sed &quot;s/ \-\-/ \\\ \n\t--/g&quot; | grep &quot;\-\-&quot; | grep -ve opt= -e param= -e build=` \
      --with-http_v3_module --with-stream_quic_module \
      --with-debug --build=nginx-quic \
      --with-cc-opt=&quot;-I/src/libressl/build/include&quot; --with-ld-opt=&quot;-L/src/libressl/build/lib&quot; --with-ld-opt=&quot;-static&quot; &amp;amp;&amp;amp; \
    make

FROM nginx
COPY --from=build /src/nginx-quic/objs/nginx /usr/sbin
RUN /usr/sbin/nginx
EXPOSE 80 443 443/udp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mind that HTTP3 uses UDP on port 443. You can leave out the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--with-debug&lt;/code&gt; option if you’re not interested in debugging. Because it’s still an experimental build, I’m leaving it.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/nginx/conf/nginx.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;worker_processes  4;

error_log  /var/log/nginx/error.log  warn;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format quic &apos;$remote_addr - $remote_user [$time_local] &apos;
                      &apos;&quot;$request&quot; $status $body_bytes_sent &apos;
                      &apos;&quot;$http_referer&quot; &quot;$http_user_agent&quot; &quot;$http3&quot;&apos;;

    access_log  /var/log/nginx/access.log  quic;

    include /etc/nginx/conf.d/*.conf;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/nginx/conf/http3.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssl_protocols TLSv1.2 TLSv1.3; # TLSv1.3 necessary for http3
quic_retry on;
ssl_early_data on;

#ssl_prefer_server_ciphers on; # Let the client choose, as of 2022-05 these ciphers are all still secure.
ssl_dhparam /etc/nginx/dhparams4096.pem; # generate with &apos;openssl dhparam -out dhparam.pem 4096&apos;
ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ecdh_curve X25519:prime256v1:secp384r1;

ssl_session_cache shared:SSL:5m;
ssl_session_timeout 1h;
ssl_session_tickets off;
ssl_buffer_size 4k; # This is for performance rather than security, the optimal value depends on each site.
                                # 16k default, 4k is a good first guess and likely more performant.

ssl_stapling on;      # As of 2022-05 this version of nginx dosen&apos;t support ssl-stapling, but it might be in the future.
ssl_stapling_verify on;
resolver 192.168.130.10 8.8.8.8 valid=300s; # Use whichever resolvers you&apos;d like, these are Cloudflare&apos;s and is one of the fastest DNS resolvers.
resolver_timeout 5s;

proxy_request_buffering off;

add_header alt-svc &apos;h3=&quot;:443&quot;; ma=86400&apos;; # Absolutely necessary header. This informs the client that HTTP/3 is available.
add_header Strict-Transport-Security max-age=15768000; # Optional but good, client should always try to use HTTPS, even for initial requests.

gzip off; #https://en.wikipedia.org/wiki/BREACH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mind that certificates will be specified by the per-server configuration file&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;letsencrypt-acme-challenge.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;location ^~ /.well-known/acme-challenge/ {
    default_type &quot;text/plain&quot;;
    root /srv/letsencrypt;
}
location = /.well-known/acme-challenge/ {
    return 404;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/nginx/conf/conf.d/sub.domain.tld&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;map $http_upgrade $connection_upgrade {
    default upgrade;
    &apos;&apos;      close;
}

server {
    listen 80;
    #listen [::]:80;
    server_name sub.domain.tld;

    # Uncomment to redirect HTTP to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen 443 http3
    listen [::]:443 ssl http2;
    listen [::]:443 http3
    server_name sub.domain.tld;

    # use a variable to store the upstream proxy
    # in this example we are using a hostname which is resolved via DNS
    # (if you aren&apos;t using DNS remove the resolver line and change the variable to point to an IP address e.g `set $jellyfin 127.0.0.1`)
    set $backend_service backend_service;
    #resolver 127.0.0.1 valid=30;

    include /etc/nginx/http3.conf;

    ssl_certificate /letsencrypt/live/sub.domain.tld/fullchain.pem;
    ssl_certificate_key /letsencrypt/live/sub.domain.tld/privkey.pem;
    ssl_trusted_certificate /letsencrypt/live/sub.domain.tld/chain.pem;

    # Security / XSS Mitigation Headers
    # NOTE: X-Frame-Options may cause issues with the webOS app
    add_header X-Frame-Options &quot;SAMEORIGIN&quot;;
    add_header X-XSS-Protection &quot;1; mode=block&quot;;
    add_header X-Content-Type-Options &quot;nosniff&quot;;

    # Content Security Policy
    # See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
    # Enforces https content and restricts JS/CSS to origin
    # External Javascript (such as cast_sender.js for Chromecast) must be whitelisted.
    # NOTE: The default CSP headers may cause issues with the webOS app
    #add_header Content-Security-Policy &quot;default-src https: data: blob: http://image.tmdb.org; style-src &apos;self&apos; &apos;unsafe-inline&apos;; script-src &apos;self&apos; &apos;unsafe-inline&apos; https://www.gstatic.com/cv/js/sender/v1/cast_sender.js https://www.gstatic.com/eureka/clank/95/cast_sender.js https://www.gstatic.com/eureka/clank/96/cast_sender.js https://www.gstatic.com/eureka/clank/97/cast_sender.js https://www.youtube.com blob:; worker-src &apos;self&apos; blob:; connect-src &apos;self&apos;; object-src &apos;none&apos;; frame-ancestors &apos;self&apos;&quot;;

    # enable Letsencrypt validation
    include /etc/nginx/letsencrypt-acme-challenge.conf;

    proxy_buffering off;

    location / {
        proxy_pass http://$backend_service:port;
        proxy_set_header Host $host;
        proxy_redirect http:// https://;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The per-service configuration files will be different depending on the actual backend service. This example is taken from my Home Assistant setup. Obviously, the domain name has to be changed but also this line might need a change:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set $backend_service backend_service;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It puts the name of the host where the service is reachable into a variable. Since Nginx is running in the host network stack, you might want to point it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Please consult the documentation of the service you want to make available.&lt;/p&gt;

&lt;h2 id=&quot;first-run&quot;&gt;First run&lt;/h2&gt;

&lt;p&gt;If you start the Nginx container now, it will fail. This is because the certificates are not yet available and the server will throw an error. To overcome this, you can run Certbot in standalone mode.&lt;/p&gt;

&lt;p&gt;Make sure port 80 is not firewalled on your server. Also, check that your router is properly forwarding the port.&lt;/p&gt;

&lt;p&gt;Try out with&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ podman run -it --rm -p 80:80 -v ~/nginx/data/letsencrypt:/etc/letsencrypt:z -v ~/nginx/log:/var/log:z certbot/certbot certonly --standalone --staging --dry-run --key-type ecdsa --rsa-key-size 4096 -d sub.domain.tld
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And do it for real with&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;podman run -it --rm -p 80:80 -v ~/nginx/data/letsencrypt:/etc/letsencrypt:z -v ~/nginx/log:/var/log:z certbot/certbot certonly --standalone --key-type ecdsa --rsa-key-size 4096 -d sub.domain.tld
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Certbot will ask you a few questions such as your e-mail address and if you could agree with their terms. I assume you do. This info will be stored so you can automate the command when renewing. You can provide multiple domains by adding extra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-d domain&lt;/code&gt; arguments.&lt;/p&gt;

&lt;p&gt;Now that you have the certificates, you can start Nginx:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[nginx] $ podman-compose --no-pod up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;automatically-start-nginx&quot;&gt;Automatically start Nginx&lt;/h2&gt;

&lt;p&gt;Podman provides a simple way to generate systemd service files. So we make use of this functionality to auto-start Nginx when booting the server:&lt;/p&gt;

&lt;p&gt;Make sure the Nginx container is still running.&lt;/p&gt;

&lt;p&gt;Go to ~/.config/systemd/user&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[~/.config/systemd/user] $ podman generate systemd --new --name --files nginx
[~/.config/systemd/user] $ systemctl --user daemon-reload
[~/.config/systemd/user] $ systemctl --user enable container-nginx.service
[~/.config/systemd/user] $ systemctl --user start container-nginx.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;automatic-renewal&quot;&gt;Automatic renewal&lt;/h2&gt;

&lt;p&gt;Certbot is not integrated into the Nginx container so we must run it separately. This is quite straightforward with Systemd timers.&lt;/p&gt;

&lt;p&gt;We’re still in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/systemd/user&lt;/code&gt; directory and create two files.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;renew-certificates.service&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Unit]
Description=Renew Let&apos;s Encrypt certificates
After=container-nginx.service

[Service]
Type=oneshot
ExecStart=podman run -it --rm -v %h/nginx/data/letsencrypt:/etc/letsencrypt:z -v %h/nginx/data/www/letsencrypt:/srv/letsencrypt:z -v %h/nginx/log:/var/log:z certbot/certbot renew --webroot -w /srv/letsencrypt
ExecStart=podman exec nginx nginx -s reload

[Install]
WantedBy=default.target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are two commands in this unit file. The first command checks for renewal. The second command reloads Nginx inside its container so new certificates are picked up. Mind that changes in configuration files are also picked up. If you made changes that contain errors, neither the changes nor new certificates are activated.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;renew-certificates.timer&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Unit]
Description=Renew Let&apos;s Encrypt certificates daily at 01:30

[Timer]
OnCalendar=*-*-* 01:30:00

[Install]
WantedBy=timers.target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Enable the timer:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ systemctl --user daemon-reload
$ systemctl --user enable renew-certificates.timer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done! Now you have a running Nginx reverse proxy with Let’s Encrypt certificates and automatic renewal.
At the time of writing, this setup has an A+ rating at &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;Qualys SSL Labs&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Switch Photo by &lt;a href=&quot;https://unsplash.com/@thomasjsn?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Thomas Jensen&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/network?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 19 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Containerized-Nginx-and-Letsencrypt</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Containerized-Nginx-and-Letsencrypt</guid>
        
        <category>Nginx</category>
        
        <category>Let&apos;s Encrypt</category>
        
        <category>HTTP3</category>
        
        <category>Podman</category>
        
        
      </item>
    
      <item>
        <title>Hardware transcoding for Jellyfin</title>
        <description>&lt;p&gt;After relying on MiniDLNA for a long time I switched to Jellyfin as my media server. And I decided to give transcoding on-the-fly a go. Getting it to work wasn’t difficult but not as easy as toggling a switch either.
How to get hardware transcoding working in Jellyfin for a J4105 processor?&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;I’m not going to go into detail on how to get Jellyfin itself up and running. Jellyfin has great documentation. IT even has a section about Podman. This itself is already remarkable. For most software “containers” as the same as Docker.&lt;/p&gt;

&lt;p&gt;I’m running Podman on Rocky Linux 9. My machine has an Intel J4105 processor.&lt;/p&gt;

&lt;p&gt;This is the command to get the container up:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ podman run \
  --cgroups=no-conmon \
  --sdnotify=conmon \
  -d \
  --rm
  --label io.containers.autoupdate=registry \
  --name jellyfin \
  --net=host \
  --user $(id -u):$(id -g) \
  --userns keep-id \
  --group-add keep-groups \
  -v /home/user/jellyfin/cache:/cache:Z \
  -v /home/user/jellyfin/config:/config:Z \
  -v /mnt/data/media:/media:ro,z \
  --device=/dev/dri/renderD128:/dev/dri/renderD128 \
  --device=/dev/dri/card0:/dev/dri/card0 \
  jellyfin/jellyfin:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s a long command but you can easily hide this in a container-compose.yml file. Or create a systemd file and run it using systemd. The command is taken from the &lt;a href=&quot;https://jellyfin.org/docs/general/administration/installing/#podman&quot;&gt;documentation&lt;/a&gt;. Changes are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;use host networking instead of just port mapping. This is to enable DLNA discovery.&lt;/li&gt;
  &lt;li&gt;use a plain volume mount for media&lt;/li&gt;
  &lt;li&gt;add the devices to the container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This last change is important of course. Without the hardware devices to transcode, you can’t use them obviously.&lt;/p&gt;

&lt;p&gt;Don’t forget to open the relevant ports in your firewall.&lt;/p&gt;

&lt;p&gt;Browse to your Jellyfin instance and add some libraries. Test and play around. I added some 4k films and enabled the DLNA server.&lt;/p&gt;

&lt;h2 id=&quot;enable-hardware-transcoding&quot;&gt;Enable hardware transcoding&lt;/h2&gt;

&lt;p&gt;As soon as I &lt;a href=&quot;https://jellyfin.org/docs/general/administration/hardware-acceleration&quot;&gt;enabled hardware transcoding&lt;/a&gt;, my (old) television refused to play the 4k movies. “This file is not supported”, it said.&lt;/p&gt;

&lt;p&gt;I had set the hardware acceleration to “Intel Quicksync (QSV)”. After all, Intel itself says &lt;a href=&quot;https://www.intel.com/content/www/us/en/products/sku/128989/intel-celeron-j4105-processor-4m-cache-up-to-2-50-ghz/specifications.html&quot;&gt;on their website&lt;/a&gt; that the processor supports it.&lt;/p&gt;

&lt;p&gt;I clearly need some extra configuration to do. There are some references in Jellyfin’s documentation but it’s not a step-by-step guide.&lt;/p&gt;

&lt;h2 id=&quot;getting-it-to-work&quot;&gt;Getting it to work&lt;/h2&gt;

&lt;h3 id=&quot;enable-driver&quot;&gt;Enable driver&lt;/h3&gt;

&lt;p&gt;The first step is to enable the driver in the kernel by setting the kernel options:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo modinfo i915 | egrep -i &quot;guc|huc|dmc&quot;

firmware:       i915/kbl_huc_4.0.0.bin
firmware:       i915/cml_huc_4.0.0.bin
firmware:       i915/icl_huc_9.0.0.bin
firmware:       i915/ehl_huc_9.0.0.bin
...
firmware:       i915/glk_dmc_ver1_04.bin
firmware:       i915/dg1_dmc_ver2_02.bin
firmware:       i915/adls_dmc_ver2_01.bin
firmware:       i915/adlp_dmc_ver2_14.bin
parm:           enable_guc:Enable GuC load for GuC submission and/or HuC load. Required functionality can be selected using bitmask values. (-1=auto [default], 0=disable, 1=GuC submission, 2=HuC load) (int)
parm:           guc_log_level:GuC firmware logging level. Requires GuC to be loaded. (-1=auto [default], 0=disable, 1..4=enable with verbosity min..max) (int)
parm:           guc_firmware_path:GuC firmware path to use instead of the default one (charp)
parm:           huc_firmware_path:HuC firmware path to use instead of the default one (charp)
parm:           dmc_firmware_path:DMC firmware path to use instead of the default one (charp)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/modprobe.d/i915.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;options i915 enable_guc=2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then update GRUB (mind that I’m on Rocky Linux, your command might need to be adapted):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo grub2-mkconfig -o /boot/efi/EFI/rocky/grub.cfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Rebuild initramfs:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo dracut --force
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then reboot.&lt;/p&gt;

&lt;p&gt;Verify:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ dmesg | grep drm
[    6.270645] systemd[1]: Starting Load Kernel Module drm...
[    6.333527] ACPI: bus type drm_connector registered
[    7.116873] i915 0000:00:02.0: [drm] couldn&apos;t get memory information
[    7.118726] i915 0000:00:02.0: [drm] Applying Increase DDI Disabled quirk
[    7.123425] i915 0000:00:02.0: [drm] Finished loading DMC firmware i915/glk_dmc_ver1_04.bin (v1.4)
[    8.233395] i915 0000:00:02.0: [drm] failed to retrieve link info, disabling eDP
[    8.261328] i915 0000:00:02.0: [drm] GuC firmware i915/glk_guc_69.0.3.bin version 69.0
[    8.261347] i915 0000:00:02.0: [drm] HuC firmware i915/glk_huc_4.0.0.bin version 4.0
[    8.275174] i915 0000:00:02.0: [drm] HuC authenticated
[    8.275189] i915 0000:00:02.0: [drm] GuC submission disabled
[    8.275193] i915 0000:00:02.0: [drm] GuC SLPC disabled
[    8.277572] [drm] Initialized i915 1.6.0 20201103 for 0000:00:02.0 on minor 0
[    8.282514] i915 0000:00:02.0: [drm] Cannot find any crtc or sizes
[    8.285528] i915 0000:00:02.0: [drm] Cannot find any crtc or sizes
[    8.287996] i915 0000:00:02.0: [drm] Cannot find any crtc or sizes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Step one is done!&lt;/p&gt;

&lt;h3 id=&quot;permissions&quot;&gt;Permissions&lt;/h3&gt;

&lt;p&gt;To avoid issues with filesystem permissions inside and outside the container I opted to just give RW access to all on both the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/dri/card0&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/dri/renderD128&lt;/code&gt;. My user had group access to both paths but the groups inside and outside the container are not the same and filesystem permissions fail. By granting everyone read and write access, this issue is out of the way.&lt;/p&gt;

&lt;p&gt;This is what it looks like on my side:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls -al /dev/dri
total 0
drwxr-xr-x.  3 root root        100 Dec 10 09:20 .
drwxr-xr-x. 21 root root       3520 Dec 10 09:20 ..
drwxr-xr-x.  2 root root         80 Dec 10 09:20 by-path
crw-rw-rw-.  1 root video  226,   0 Dec 10 09:20 card0
crw-rw-rw-.  1 root render 226, 128 Dec 10 09:20 renderD128
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;selinux&quot;&gt;SELinux&lt;/h3&gt;

&lt;p&gt;Playback still doesn’t work. A common trick I try is to temporarily disable SELinux.
Also this time: magic! Transcoding works!&lt;/p&gt;

&lt;p&gt;And now we need to enable SELinux again.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo setsebool -P container_use_devices=true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo ausearch -c &apos;ffmpeg&apos; --raw | audit2allow -M ffmpeg-renderD128
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i ffmpeg-renderD128.pp
$ sudo semodule -i ffmpeg-renderD128.pp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Don’t forget to re-enable SELinux.&lt;/p&gt;

&lt;h2 id=&quot;done&quot;&gt;Done!&lt;/h2&gt;

&lt;p&gt;You can now enjoy hardware-supported transcoding in Jellyfin on your J4105 machine.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Chip Photo by &lt;a href=&quot;https://unsplash.com/@briankost?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Brian Kostiuk&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/processor?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 10 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Jellyfin-hardware-transcoding</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Jellyfin-hardware-transcoding</guid>
        
        <category>Jellyfin</category>
        
        <category>Podman</category>
        
        <category>SELinux</category>
        
        
      </item>
    
      <item>
        <title>RHEL 9 and msmtp</title>
        <description>&lt;p&gt;I use &lt;a href=&quot;https://marlam.de/msmtp/&quot;&gt;msmtp&lt;/a&gt; as a simple SMTP relay to forward system messages to my Gmail address. After upgrading Rocky Linux to version 9, I noticed msmtp isn’t (yet?) available in the repositories. So I built it myself.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h3 id=&quot;my-first-rpm-ever&quot;&gt;My first rpm ever&lt;/h3&gt;

&lt;p&gt;I surely could download the source code and install all the dependencies and tools to build and install. However, I don’t want to clutter my base system with all these one-time tools. So I decided to build it in a container. I’m way out of my comfort zone here.&lt;/p&gt;

&lt;p&gt;After some trial and error and browsing for solutions, I ended up with this result.&lt;/p&gt;

&lt;h3 id=&quot;preparation&quot;&gt;Preparation&lt;/h3&gt;

&lt;p&gt;I’m building on the server so all the action below is done over an ssh connection.
At the time of writing, the latest version of msmtp is 1.8.22.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir -p msmtp/{build,src} &amp;amp;&amp;amp; cd msmtp
$ touch Containerfile build.bash build/build_rpm.bash build/msmtp.spec
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You now should have the following layout:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ -- msmtp
       |
       +-- build
       |     |
       |     +-- build_rpm.bash
       |     +-- msmtp.spec
       +-- src (empty dir)
       +-- Containerfile
       +-- build.bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s see what should be in the files.&lt;/p&gt;

&lt;h4 id=&quot;containerfile&quot;&gt;Containerfile&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FROM rockylinux:9
RUN dnf install -y epel-release dnf-plugins-core
RUN dnf config-manager --set-enabled crb
RUN dnf install -y rpm-build redhat-rpm-config make gcc nano git tar unzip rpmlint autoconf automake libtool &amp;amp;&amp;amp; \
    dnf clean all
RUN mkdir -p /rpmbuild/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
COPY build/build_rpm.bash /rpmbuild/build_rpm.bash
COPY build/msmtp.spec /rpmbuild/msmtp.spec
ADD src /rpmbuild/rpmbuild/SOURCES/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Breakdown of the Containerfile: We start from the same base system as we’re going to run the result on. Next, we enable extra repos to be able to find msmtp’s dependencies and the developer tools. (Red Hat calls this CRB or CodeReady Linux Builder repository.) We’re then able to install everything we need to build the rpm.&lt;/p&gt;

&lt;p&gt;All that’s left is to prepare the directory structure and copy/add all the files.&lt;/p&gt;

&lt;h4 id=&quot;buildbash&quot;&gt;build.bash&lt;/h4&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PACKAGE_TO_BUILD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;msmtp

&lt;span class=&quot;c&quot;&gt;# directory where the rpm will be stored&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; artifacts &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; artifacts
&lt;span class=&quot;k&quot;&gt;fi
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;artifacts
&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;777 artifacts

&lt;span class=&quot;c&quot;&gt;# First build an image that contains the sources and necessary packages for rpmbuild&lt;/span&gt;
podman build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE_TO_BUILD&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-build&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# then run the image&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$WORKSPACE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;WORKSPACE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi
&lt;/span&gt;podman run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PACKAGE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE_TO_BUILD&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;WORKSPACE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/artifacts:/artifacts:Z &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE_TO_BUILD&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-build&lt;/span&gt; /rpmbuild/build_rpm.bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the script that eventually will launch the container to build the rpm. It’s simple. All it does is create an output directory, build the image and run the image. Nothing special here.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod +x&lt;/code&gt; so the file is executable.&lt;/p&gt;

&lt;h4 id=&quot;buildbuild_rpmbash&quot;&gt;build/build_rpm.bash&lt;/h4&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# check if spec file is present&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /rpmbuild
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; ./&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.spec &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;Sorry, can not find rpm spec file
 &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.spec /rpmbuild/rpmbuild/SPECS
dnf builddep &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.spec

&lt;span class=&quot;c&quot;&gt;# then execute the rpmbuild command&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;rpmbuild
rpmbuild &lt;span class=&quot;nt&quot;&gt;-ba&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--define&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_topdir &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; ./SPECS/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.spec
&lt;span class=&quot;c&quot;&gt;# copy the rpms to the artifact directory.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /artifacts &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; ./RPMS/x86_64/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PACKAGE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}*&lt;/span&gt;.rpm /artifacts/
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s again a quite short script. It performs a check for the .spec file and then installs the dependencies that are specified in that spec file.
When that’s done, the rpm is built and copied into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;artifacts&lt;/code&gt; directory (which is created by the build.bash script above)&lt;/p&gt;

&lt;p&gt;Don’t forget to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod +x&lt;/code&gt; the file.&lt;/p&gt;

&lt;h4 id=&quot;msmtpspec&quot;&gt;msmtp.spec&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Name:           msmtp
Version:        1.8.22
Release:        1%{?dist}
Summary:        SMTP client
License:        GPLv3+
URL:            https://marlam.de/%{name}/
Source0:        https://marlam.de/%{name}/releases/%{name}-%{version}.tar.xz
#Patch1:        msmtp-0001-Fix-linking-w-o-gsasl.patch

BuildRequires: make
%if 0%{?el5}
BuildRequires:  openssl-devel
%else
BuildRequires:  gnutls-devel
%endif

BuildRequires:  autoconf
BuildRequires:  automake
BuildRequires:  gcc
BuildRequires:  gettext-devel
BuildRequires:  libidn-devel
BuildRequires:  libgsasl-devel
BuildRequires:  libsecret-devel

Requires(post):         %{_sbindir}/alternatives
Requires(postun):       %{_sbindir}/alternatives

%description
It forwards messages to an SMTP server which does the delivery.
Features include:
  * Sendmail compatible interface (command line options and exit codes).
  * Authentication methods PLAIN,LOGIN,CRAM-MD5,DIGEST-MD5,GSSAPI,and NTLM
  * TLS/SSL both in SMTP-over-SSL mode and in STARTTLS mode.
  * Fast SMTP implementation using command pipe-lining.
  * Support for Internationalized Domain Names (IDN).
  * DSN (Delivery Status Notification) support.
  * RMQS (Remote Message Queue Starting) support (ETRN keyword).
  * IPv6 support.

%prep
%autosetup -p1

%build
autoreconf -ivf
%configure --disable-rpath --with-libsecret --with-libgsasl %{?el5:--with-ssl=openssl}
make %{?_smp_mflags}

%install
make install DESTDIR=%{buildroot} INSTALL=&apos;install -p&apos;
rm -f scripts/Makefile*
%find_lang %{name}
rm -f %{buildroot}%{_infodir}/dir

# setup dummy files for alternatives
touch %{buildroot}%{_bindir}/msmtp

%post
%{_sbindir}/update-alternatives --install %{_sbindir}/sendmail mta %{_bindir}/msmtp 40 \
  --slave %{_prefix}/lib/sendmail mta-sendmail %{_bindir}/msmtp \
  --slave %{_mandir}/man8/sendmail.8.gz mta-sendmailman %{_mandir}/man1/msmtp.1.gz \
  --slave %{_bindir}/mailq mta-mailq %{_bindir}/msmtp \
  --slave %{_mandir}/man1/mailq.1.gz mta-mailqman %{_mandir}/man1/msmtp.1.gz

%postun
if [ $1 -eq 0 ] ; then
        %{_sbindir}/update-alternatives --remove mta %{_bindir}/msmtp
fi

%files -f %{name}.lang
%license COPYING
%doc AUTHORS NEWS README THANKS scripts
%doc doc/msmtprc-system.example doc/msmtprc-user.example
%{_bindir}/%{name}*
%{_infodir}/%{name}.info*
%{_mandir}/man1/%{name}*.1*

%changelog
* Wed Aug 10 2022 My Name &amp;lt;e_mail@domain.com&amp;gt; - 1.8.22-1
- Ver. 1.8.22
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I copied this file from Fedora’s source and happened to work on RHEL9 which isn’t a surprise of course.&lt;/p&gt;

&lt;h3 id=&quot;get-the-source&quot;&gt;Get the source&lt;/h3&gt;

&lt;p&gt;One last thing before building it is getting the actual source code. So download the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tar.xz&lt;/code&gt; file &lt;a href=&quot;https://marlam.de/msmtp/download/&quot;&gt;here&lt;/a&gt; and put it in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt; directory. You don’t need to untar.&lt;/p&gt;

&lt;h3 id=&quot;build&quot;&gt;Build!&lt;/h3&gt;

&lt;p&gt;Now, just run the script:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./build.bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It builds an image called “msmtp-build”. Then creates a container that builds the rpm (and destroys the container afterwards).&lt;/p&gt;

&lt;p&gt;Install msmtp by a simple:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo dnf install artifacts/msmtp-1.8.22-1.el9.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done! Configure msmtp the same way as on other Linux systems as &lt;a href=&quot;https://bert.emelis.net/posts/1-MSMTP&quot;&gt;I did here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of copy-pasting, you can download the whole set of files from my Github: &lt;a href=&quot;https://github.com/bertmelis/build-msmtp&quot;&gt;build-msmtp&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;
</description>
        <pubDate>Tue, 23 Aug 2022 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-RHEL9-and-msmtp</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-RHEL9-and-msmtp</guid>
        
        <category>Rocky Linux</category>
        
        <category>msmtp</category>
        
        
      </item>
    
      <item>
        <title>Pihole and OpenWRT</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://pi-hole.net/&quot;&gt;Pi-hole&lt;/a&gt; is a DNS server you run on your own network which filters out any unwanted lookups and therefore reduces your bandwidth usage. I installed it in a Podman container and configured my OpenWRT box.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h3 id=&quot;preparation&quot;&gt;Preparation&lt;/h3&gt;

&lt;p&gt;My server runs on &lt;a href=&quot;/posts/1-Rocky-Linux&quot;&gt;Rocky Linux&lt;/a&gt; and Podman is supported out of the box. Check &lt;a href=&quot;https://podman.io/getting-started/installation&quot;&gt;Podman’s documentation&lt;/a&gt; to install it if needed.&lt;/p&gt;

&lt;p&gt;Download the Pi-hole image. Probably it’ll be fetched from the &lt;em&gt;Docker&lt;/em&gt; registry but it is compatible.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ podman pull pihole/pihole
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create directories to have your settings persisted. My Podman containers run under my user, data is in my home directory.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir /home/&amp;lt;username&amp;gt;/pihole
$ mkdir /home/&amp;lt;username&amp;gt;/pihole/dnsmasq
$ mkdir /home/&amp;lt;username&amp;gt;/pihole/pihole
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, give the directories proper permissions. Because Podman does not run as admin, it cannot write to the newly created directories. Inside the container, Pi-hole runs as user &lt;em&gt;pihole&lt;/em&gt;. To the outside world, this user is mapped to a &lt;em&gt;fictive&lt;/em&gt; user with id 100998:100998. This is how it is mapped on my system.&lt;/p&gt;

&lt;p&gt;Adjust the permissions accordingly:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo chown -R 100998:100998 ~/pihole/*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;open-relevant-ports-on-your-server&quot;&gt;Open relevant ports on your server&lt;/h4&gt;

&lt;p&gt;Via the cockpit GUI, go to “Networking”. In the section “Firewall”, click “Edit rules and zones”. From there add port 80 (only TCP) for Pi-hole’s web GUI and port 53 (TCP and UDP) for the DNS server.&lt;/p&gt;

&lt;h3 id=&quot;start-pi-hole&quot;&gt;Start Pi-hole&lt;/h3&gt;

&lt;p&gt;Starting is done by one command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ podman run --init -d --restart=always --net=host -e TZ=Europe/Warsaw -e WEBPASSWORD=&amp;lt;yourpassword&amp;gt; -e SERVERIP=&amp;lt;yourserverip&amp;gt; -v ~/pihole/pihole:/etc/pihole:Z -v ~/pihole/dnsmasq:/etc/dnsmasq.d:Z --name=pihole pihole/pihole
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mind there is no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; here. Most of the options explain themselves. The password and server’s IP address need to be set to your wish.&lt;/p&gt;

&lt;p&gt;You can already browse the Pi-hole web interface. Be sure to test this.&lt;/p&gt;

&lt;p&gt;If you see the webpage showing up, create a service so Pi-hole starts automatically whenever your server reboots. (Remember, you have automatic security updates enabled. This can cause restarts!)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd ~/.config/systemd/user
$ podman generate systemd --new --name --files pihole
$ systemctl --user daemon-reload
$ systemctl --user enable container-pihole.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;adjust-the-network-settings&quot;&gt;Adjust the network settings&lt;/h3&gt;

&lt;p&gt;My router runs on &lt;a href=&quot;https://openwrt.org&quot;&gt;OpenWRT&lt;/a&gt;. All we need to do here is add a DHCP option so the router tells all clients to use Pi-hole as the DNS server.&lt;/p&gt;

&lt;p&gt;Go to Network –&amp;gt; Interfaces. Click “Edit” on the LAN interface. In the “DHCP Server” tab, choose the “Advanced Settings” tab.&lt;/p&gt;

&lt;p&gt;Here the screen already tells you how to do it: Add “6,&lt;yourserverip&gt;&quot; as an option and hit &quot;Save&quot;.&lt;/yourserverip&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/pihole/dhcp.jpg&quot; alt=&quot;DHCP options&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;rogue-devices&quot;&gt;Rogue devices&lt;/h4&gt;

&lt;p&gt;Some devices have hardcoded DNS servers, Google devices among them. You can force them to use Pi-hole using the firewall on OpenWRT.&lt;/p&gt;

&lt;p&gt;Go to Network –&amp;gt; Firewall and select the “Custom Rules” tab. Add the following rules:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -t nat -I PREROUTING -i br-lan -p tcp --dport 53 -j DNAT --to &amp;lt;yourserverip&amp;gt;
iptables -t nat -I PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to &amp;lt;yourserverip&amp;gt;
iptables -t nat -I PREROUTING -i br-lan -p tcp -s &amp;lt;yourserverip&amp;gt; --dport 53 -j ACCEPT
iptables -t nat -I PREROUTING -i br-lan -p udp -s &amp;lt;yourserverip&amp;gt; --dport 53 -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It will forward traffic destined to outside DNS servers back to your Pi-hole instance.&lt;/p&gt;

&lt;h3 id=&quot;what-about-dhcp&quot;&gt;What about DHCP?&lt;/h3&gt;

&lt;p&gt;In my setup, DHCP is still managed by OpenWRT. That’s because I have multiple VLANs with different subnets. Pi-hole lacks the functionality to handle them and I like to keep things together.&lt;/p&gt;

&lt;h3 id=&quot;pi-hole-configuration&quot;&gt;Pi-hole configuration&lt;/h3&gt;

&lt;p&gt;A few things still need to be configured on the Pi-hole side.&lt;/p&gt;

&lt;p&gt;Log in to Pi-hole (http://&lt;yourserverip&gt;/admin/) and go to &quot;Local DNS&quot; --&amp;gt; &quot;DNS Records&quot;. Any hostnames you had in your network can be defined here.&lt;/yourserverip&gt;&lt;/p&gt;

&lt;p&gt;In “Settings” –&amp;gt; “DNS” you need to define the upstream DNS servers. I use the servers given by my ISP. You can use &lt;a href=&quot;https://developers.google.com/speed/public-dns&quot;&gt;Google’s&lt;/a&gt; or &lt;a href=&quot;https://use.opendns.com/&quot;&gt;OpenDNS’s&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One last thing is “Conditional forwarding”. Since we’re not using Pi-hole as our DHCP server, it doesn’t know about client names, only about IP addresses. This can be tiresome to analyze the traffic as “Wife’s phone” is easier to understand than “192.168.1.125”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/pihole/cond.jpg&quot; alt=&quot;Conditional forwarding&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Add your network configuration and the IP address of your DHCP server (which is my router’s).&lt;/p&gt;

&lt;p&gt;If you restart your computer and are still able to browse on the Internet, you’re done!&lt;/p&gt;

&lt;hr /&gt;
</description>
        <pubDate>Tue, 01 Mar 2022 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Pihole-and-OpenWRT</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Pihole-and-OpenWRT</guid>
        
        <category>Pihole</category>
        
        <category>OpenWRT</category>
        
        <category>Podman</category>
        
        
      </item>
    
      <item>
        <title>Finishing Rocky setup</title>
        <description>&lt;p&gt;After the basic installation of Rocky Linux, it’s time to finish the setup. We’re preparing the system to actually deploy useful stuff.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h3 id=&quot;check&quot;&gt;Check&lt;/h3&gt;

&lt;p&gt;when you finished the &lt;a href=&quot;/posts/1-Rocky-Linux&quot;&gt;basic setup&lt;/a&gt;, you can log in via the terminal or the web GUI (Cockpit). Check basic settings like &lt;em&gt;hostname&lt;/em&gt;, &lt;em&gt;time and timezone&lt;/em&gt; and so on.&lt;/p&gt;

&lt;p&gt;Cockpit shows some statistics about your system. If you want to persist them you’ll have to install &lt;strong&gt;pcp&lt;/strong&gt;. this can be done through the GUI. Alternatively, install &lt;strong&gt;cockpit-pcp&lt;/strong&gt; using the command line:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo yum install cockpit-pcp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the “Software updates” tab in the GUI, I also enabled automatic software updates (for security-related updates) and kernel patches. As the screen tells you, this means the server will reboot from time to time. Keep this in mind when you manually start programs you rely on. On the same page, you can do a manual update.&lt;/p&gt;

&lt;h3 id=&quot;add-disks&quot;&gt;Add disks&lt;/h3&gt;

&lt;p&gt;Before adding my data disk (in the OS, that is), I added the relevant Cockpit addon and &lt;em&gt;smartmontools&lt;/em&gt;. The disk supports SMART.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo yum smartmontools cockpit-storaged
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a mount point:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo mkdir /mnt/data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now add the disk. First, find its UUID.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo blkid
/dev/sdb1: UUID=&quot;1fdd1ceb-70e8-476b-819d-d7082c7b4749&quot; BLOCK_SIZE=&quot;4096&quot; TYPE=&quot;ext4&quot; PARTUUID=&quot;4f330730-6bd1-4325-9343-37242b985408&quot;
/dev/sda1: UUID=&quot;D41A-D5C0&quot; BLOCK_SIZE=&quot;512&quot; TYPE=&quot;vfat&quot; PARTLABEL=&quot;EFI System Partition&quot; PARTUUID=&quot;fca2473b-8a02-4600-a776-d9e58b572b32&quot;
/dev/sda2: UUID=&quot;106247eb-24a7-4d88-857b-937a09100aba&quot; BLOCK_SIZE=&quot;512&quot; TYPE=&quot;xfs&quot; PARTUUID=&quot;429fe31a-6a8b-4682-8103-a646248bc767&quot;
/dev/sda3: UUID=&quot;9RG0BQ-1yKg-Nem8-O1vF-f20Q-YI45-WWJ7t7&quot; TYPE=&quot;LVM2_member&quot; PARTUUID=&quot;99e3b950-819c-428e-a391-6f962dbbfc1f&quot;
/dev/mapper/rl_server-root: UUID=&quot;89b352ee-e051-4a94-bb3e-87d6348dc8d9&quot; BLOCK_SIZE=&quot;512&quot; TYPE=&quot;xfs&quot;
/dev/mapper/rl_server-swap: UUID=&quot;91074d79-f7f3-4ec2-a824-2c530aec8ad7&quot; TYPE=&quot;swap&quot;
/dev/mapper/rl_server-home: UUID=&quot;43034b2e-0af3-49be-be5a-c4b7ed46b0aa&quot; BLOCK_SIZE=&quot;512&quot; TYPE=&quot;xfs&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The top entry is the right one. It’s the only one with ext4. I know the drive is formatted like that. If you’re unsure, manually mount and check. Add it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstab&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo nano /etc/fstab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add a line like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;UUID=1fdd1ceb-70e8-476b-819d-d7082c7b4749 /mnt/data auto nofail,noatime,noexec,errors=remount-ro 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Every item is separated by a space. Some explanation:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;UUID&lt;/strong&gt;: the long code found by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blkid&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;mount point&lt;/strong&gt;: where in the filesystem will the disk be attached&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;filesystem type&lt;/strong&gt;:  etx4 or leave auto&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;options&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;nofail: ignore errors at boot when the disk is not there&lt;/li&gt;
      &lt;li&gt;noatime: don’t save access time (files and dirs)&lt;/li&gt;
      &lt;li&gt;noexec: don’t allow executables on this drive&lt;/li&gt;
      &lt;li&gt;errors=remount-ro: when errors are encountered, remount the drive read-only to avoid further damage&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;0&lt;/strong&gt;: dump, leave disabled&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;0&lt;/strong&gt;: fsck, set to zero to skip checks at boot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want it, you can also use the disk’s SMART capabilities:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo systemctl start smartd
$ sudo systemctl enable smartd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;podman&quot;&gt;Podman&lt;/h3&gt;

&lt;p&gt;On my Debian installation, I ran Podman and a few virtual machines. It’s my goal to move everything to &lt;a href=&quot;https://podman.io/&quot;&gt;Podman&lt;/a&gt;. Podman is Redhat’s Docker. It runs daemonless and is capable of running rootless. These are advantages but might bring some difficulties, especially with SELinux. We’ll see where it goes.&lt;/p&gt;

&lt;p&gt;At least installation is simple:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo yum install podman cockpit-podman
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Adjust the port range Podman is allowed to use:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo nano /etc/sysctl.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;net.ipv4.ip_unprivileged_port_start=80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And reload&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo sysctl --system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;on-last-thing&quot;&gt;On last thing&lt;/h3&gt;

&lt;p&gt;While we’re at it, we might want to enable the “extra packages for enterprise linux”. Up to now we didn’t need any extra packages but we might run into this in the future and who knows, cause some head scratching. It doesn’t hurt to enable it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo yum install epel-release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;Photo Hercule’s Rock by Dzidek Lasek, https://pixabay.com/photos/paternal-national-park-autumn-2742115/&lt;/p&gt;
</description>
        <pubDate>Wed, 01 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Finishing-Rocky</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Finishing-Rocky</guid>
        
        <category>Rocky Linux</category>
        
        
      </item>
    
      <item>
        <title>Moved to Rocky Linux</title>
        <description>&lt;p&gt;I’ve always been a big fan of Debian’s ultra-stability. But stability came with Debian’s number one downside: old packages. I took a leap of faith and switched to Rocky Linux.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h3 id=&quot;step-1-backup&quot;&gt;Step 1: Backup&lt;/h3&gt;

&lt;p&gt;Although my data is on a separate drive, I backed up everything. Not only data (documents, music, pictures…) but also all my settings (Containerfiles and volumes most notably).&lt;/p&gt;

&lt;h3 id=&quot;step-2-installation&quot;&gt;Step 2: Installation&lt;/h3&gt;

&lt;p&gt;Rocky Linux has plenty of documentation and this obviously included the installation procedure. Mind that for installation I use a monitor, keyboard and mouse.&lt;/p&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://rockylinux.org/download/&quot;&gt;Download&lt;/a&gt; the appropriate image. I chose the minimal version&lt;/li&gt;
  &lt;li&gt;Flash to a USB drive (I use BalenaEtcher for this)&lt;/li&gt;
  &lt;li&gt;Reboot the server and adjust the boot settings in BIOS to boot from the USB drive&lt;/li&gt;
  &lt;li&gt;Reboot again and follow the on-screen instructions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Things I did during installation:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Enable network. My server gets its IP via DHCP but with a static lease it always gets the same address.&lt;/li&gt;
  &lt;li&gt;Adjust the timezone, and enable network time. Mind that you first have to enable &lt;em&gt;network&lt;/em&gt; before enabling &lt;em&gt;network time&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Enable “Security Policy”. This enables SELinux.&lt;/li&gt;
  &lt;li&gt;Software Selection: set it to “Minimal Install”. I’m freaky about this. If you’re more relaxed you could opt for “Server”.&lt;/li&gt;
  &lt;li&gt;Keep the root account disabled&lt;/li&gt;
  &lt;li&gt;Create a non-root account but make it an administrator&lt;/li&gt;
  &lt;li&gt;Select the “Installation Destination”. On My system, I’ve got two disks: one for the OS and related and one for data. Obviously, I select the OS drive and opt for automatic storage configuration. I don’t want to preserve anything so I “reclaim” all space on the drive. This deletes everything that is currently on the drive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click “Begin Installation” and done.&lt;/p&gt;

&lt;h3 id=&quot;step-3-finish-setup&quot;&gt;Step 3: Finish setup&lt;/h3&gt;

&lt;p&gt;After rebooting, your trusted but boring login screen will be served. But this is not Debian anymore. We can now have a built-in management interface.&lt;/p&gt;

&lt;p&gt;Install by&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo yum install cockpit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And enable by&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo enable cockpit.socket
sudo systemctl start cockpit.socket
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can now browse to http://your.server.ip:9090. Cockpit will add a firewall rule to allow traffic to port 9090.&lt;/p&gt;

&lt;p&gt;Et voilà, you’re ready to go.&lt;/p&gt;

&lt;h3 id=&quot;attention&quot;&gt;Attention!&lt;/h3&gt;

&lt;p&gt;Rocky Linux comes with SELinux. It can be really annoying but that’s a good thing.
If you would like to enable TLS on your cockpit GUI, you might experience the joys of dealing with SELinux.
Imagine you upload your certificate to your home directory and move it into place from there. Then your file doesn’t have the right label and Cockpit won’t be able to read it.
Cockpit will only give you an error saying it failed to start. Whether this is SELinux-related or not, you can easily check by running&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo setenforce 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Probably cockpit will happily serve you the webpage over TLS. But we want to enable SELinux again so we have to restore the file labels:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo restorecon -rv F /etc/cockpit
restorecon: lstat(/etc/cockpit/F) failed: No such file or directory
Relabeled /etc/cockpit/ws-certs.d/your-cert.cert from unconfined_u:object_r:user_home_t:s0 to unconfirmed_u:object_r:etc_t:s0
Relabeled /etc/cockpit/ws-certs.d/your-cert.key from unconfined_u:object_r:user_home_t:s0 to unconfirmed_u:object_r:etc_t:s0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can now enable SELinux again using Cockpit or on the command line (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo setenforce 1&lt;/code&gt;).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Photo Morskie Oko by Greg Trowman, https://unsplash.com/photos/D9QmRGgxRkk&lt;/p&gt;
</description>
        <pubDate>Thu, 18 Nov 2021 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Rocky-Linux</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Rocky-Linux</guid>
        
        <category>Rocky Linux</category>
        
        
      </item>
    
      <item>
        <title>Self signed certificates in Windows 11</title>
        <description>&lt;p&gt;If you generate your own, self-signed root certificate Windows will complain about it because Windows doesn’t trust you.
It is a good thing but it also is annoying. I’ll show you how you can add your self-signed certificate to the certificate store so 
Windows 11 will trust you.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;After following &lt;a href=&quot;https://bert.emelis.net/posts/1-Certificate-management&quot;&gt;this guide&lt;/a&gt; you have your own, self-signed certificate. It’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/keys/ca/root-ca.crt&lt;/code&gt; file. There are a few steps to follow but none of them involves a command line.&lt;/p&gt;

&lt;p&gt;I created this guide on Windows 11, Windows 10 should also be OK.&lt;/p&gt;

&lt;h3 id=&quot;open-the-microsoft-management-console&quot;&gt;Open the Microsoft Management Console&lt;/h3&gt;

&lt;p&gt;Open the “start menu” and type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmc&lt;/code&gt;. Windows will search for a program that matches “mmc”. Click the icon with the red toolbox. This will open the “Microsoft Management Console” which looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/01-mmc.png&quot; alt=&quot;Microsoft Management Console&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;add-certificate-manager&quot;&gt;Add certificate manager&lt;/h3&gt;

&lt;p&gt;In the MMC, go to “File” » “Add/Remove Snap-in”. A new window will open.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/02-snapin.png&quot; alt=&quot;Microsoft Management Console&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From the list of snap-ins, chose “Certificates” and click “Add” and follow the wizard:&lt;/p&gt;

&lt;p&gt;Select “Computer account”
&lt;img src=&quot;/assets/images/posts/certswin/03-compacc.png&quot; alt=&quot;Computer account&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And next chose “Local computer” (no other choices are available.) and click “Finish”.
&lt;img src=&quot;/assets/images/posts/certswin/04-localcomp.png&quot; alt=&quot;Local computer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The snap-in is added, you can now click “OK
&lt;img src=&quot;/assets/images/posts/certswin/05-ok.png&quot; alt=&quot;OK&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;list-certificates&quot;&gt;List certificates&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/06-certificates.png&quot; alt=&quot;Certificates&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can now browse through the already available certificates. In the middle pane, double click “Certificates (local Computer)” and then “Trusted Root Certificate Authorities” and finally “Certificates”. you’ll see a list of all root CAs the computer trusts. We created our own root certificate authority so we will have to add ours here.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/07-certificatesopen.png&quot; alt=&quot;Certificates open&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;add-our-root-ca&quot;&gt;Add our Root CA&lt;/h3&gt;

&lt;p&gt;With the list of certificates in the middle pane, right-click on “Certificates” in the left pane, go the “All Tasks” and “Import”. Alternatively, you can select “Action” from the top menu bar, go to “All Tasks” and finally “Import”. Follow the wizard.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/08-import1.png&quot; alt=&quot;Import wizard 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click “Next”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/09-import2.png&quot; alt=&quot;Import wizard 2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Browse to your root certificate (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keys/ca/root-ca.crt&lt;/code&gt;) and click “Next”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certswin/10-import3.png&quot; alt=&quot;Import wizard 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click “Next” again. The wizard already selected the right option for us to store the new certificate in the right store.&lt;/p&gt;

&lt;h3 id=&quot;check-and-done&quot;&gt;Check and done!&lt;/h3&gt;

&lt;p&gt;Your certificate is now added to Windows. Your computer will now trust all the certificates that have been signed by this root certificate (and derivates). You might need to restart your browser for it to work with the newly added certificate.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;small&gt;Notary sign image by &lt;a href=&quot;https://pixabay.com/users/tama66-1032521/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3617525&quot;&gt;Peter H&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3617525&quot;&gt;Pixabay&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Nov 2021 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Add-root-CA-to-Windows-11</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Add-root-CA-to-Windows-11</guid>
        
        <category>self-signed</category>
        
        <category>certificates</category>
        
        <category>Windows</category>
        
        
      </item>
    
      <item>
        <title>Self signed certificates in Firefox Ubuntu</title>
        <description>&lt;p&gt;Even if you have imported your self-signed root certificate to your Ubuntu system, Firefox won’t use it. This has to be solved and I found a way.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;You could just add an exception for your website to Firefox, but it still shows the little warning icon in the address bar to show something is fishy.&lt;/p&gt;

&lt;p&gt;Firefox uses its own certificate store and doesn’t care about the certificates the system trusts.&lt;/p&gt;

&lt;p&gt;Luckily, &lt;a href=&quot;https://askubuntu.com/questions/244582/add-certificate-authorities-system-wide-on-firefox&quot;&gt;this answer on Ask Ubuntu&lt;/a&gt; has the path to the answer. At the time of writing, the answer is not the accepted one, nor has it a high rating. But in my opinion, it is the best one.&lt;/p&gt;

&lt;p&gt;Even &lt;a href=&quot;https://support.mozilla.org/en-US/kb/setting-certificate-authorities-firefox&quot;&gt;Mozilla’s website&lt;/a&gt; mentions it.&lt;/p&gt;

&lt;h2 id=&quot;install-the-replacement-lib&quot;&gt;Install the replacement lib&lt;/h2&gt;

&lt;p&gt;The trick is changing Firefox’s behaviour by using another certificate management library.&lt;/p&gt;

&lt;p&gt;The replacement lib is to be found on &lt;a href=&quot;https://p11-glue.github.io/p11-glue/p11-kit.html&quot;&gt;their website&lt;/a&gt; or on their &lt;a href=&quot;https://github.com/p11-glue/p11-kit&quot;&gt;Github page&lt;/a&gt;. The lib is also available on Ubuntu’s repositories.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apt install p11-kit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On my system, it was already installed. Yeah!&lt;/p&gt;

&lt;h2 id=&quot;instruct-firefox-to-use-the-p11-kit&quot;&gt;Instruct Firefox to use the p11-kit&lt;/h2&gt;

&lt;p&gt;Unlike the Ask Ubuntu answer (which is already a few years old), Firefox has the option to import security modules. So we’ll include the P11-kit module to import the certificates from our system into Firefox.&lt;/p&gt;

&lt;h3 id=&quot;open-the-settings-page-in-firefox&quot;&gt;Open the settings page in Firefox&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/1-preferences.jpg&quot; alt=&quot;Preferences&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;click-privacy--security-and-scroll-to-security&quot;&gt;Click “Privacy &amp;amp; Security” and scroll to “Security”&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/2-security.jpg&quot; alt=&quot;Security settings&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;view-certificates&quot;&gt;View certificates&lt;/h3&gt;

&lt;p&gt;When you click “View Certificates” you’ll get a list with all the trusted root certificates. Yours will not be in the list.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/3-certificates.jpg&quot; alt=&quot;Certificates list&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Close this screen.&lt;/p&gt;

&lt;h3 id=&quot;add-the-custom-module&quot;&gt;Add the custom module&lt;/h3&gt;

&lt;p&gt;Back in the settings screen, click “Security Devices”. you’ll get a screen with all the modules that take care of certificate management.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/4-load.jpg&quot; alt=&quot;Security devices&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click “Load”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/5-kit.jpg&quot; alt=&quot;Add kit&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Give the added module a sensible name and add the path to the P11-kit module:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Module name: P11 kit&lt;/li&gt;
  &lt;li&gt;Module filename: /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click “OK” The Device manager now shows the included module with its certificate source.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/6-added.jpg&quot; alt=&quot;Added module&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;check-certificates&quot;&gt;Check certificates&lt;/h3&gt;

&lt;p&gt;when you click “View Certificates” in the settings screen, you can find your self-signed root certificate in the certificates list.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/firefox/7-certificates.jpg&quot; alt=&quot;Certificates&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unlike the answer on Ask Ubuntu, the added module is a setting that survives updates.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;small&gt;Notary sign image by &lt;a href=&quot;https://pixabay.com/users/tama66-1032521/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3617525&quot;&gt;Peter H&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3617525&quot;&gt;Pixabay&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 21 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/2-Firefox-and-self-signed-certificates</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/2-Firefox-and-self-signed-certificates</guid>
        
        <category>self-signed</category>
        
        <category>certificates</category>
        
        <category>Firefox</category>
        
        <category>Ubuntu</category>
        
        
      </item>
    
      <item>
        <title>Certificate management</title>
        <description>&lt;p&gt;OpenSSL and certificate management are a black box to me. So I thought I’d better write down how I managed to create my certificates. I followed this tutorial: &lt;a href=&quot;https://pki-tutorial.readthedocs.io/en/latest/index.html&quot;&gt;https://pki-tutorial.readthedocs.io/en/latest/index.html&lt;/a&gt;.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;There are a lot of OpenSSL tutorials online to create your self-signed certificates. And in fact, when you have a public-facing service you’d better stick to trusted platforms like &lt;a href=&quot;https://www.letsencrypt.org&quot;&gt;Let’s Encrypt&lt;/a&gt;. For our internal services, I’m trustworthy enough to have my own certificate authority. I want to create certificates for my OpenVPN server, my Mosquitto broker and the Cockpit control panel.&lt;/p&gt;

&lt;p&gt;DISCLAIMER: The following steps are from &lt;a href=&quot;https://pki-tutorial.readthedocs.io/en/latest/index.html&quot;&gt;https://pki-tutorial.readthedocs.io/en/latest/index.html&lt;/a&gt;. They are more elaborate than most other guides but the steps are clear and understandable and you learn how the chain of trust works.&lt;/p&gt;

&lt;p&gt;ATTENTION: Private keys are to be kept strictly private so you don’t want the key files to be exposed to the Internet. It is best to set up the key infrastructure on a computer that is not connected to the Internet to prevent any unauthorized access. Alternatively, instead of generating the PKI in your home directory, you can put all the files on removable media like a USB stick and store it somewhere safe.&lt;/p&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;p&gt;You probably already have everything installed on your system. I’m creating the certificates on my Lubuntu laptop and afterwards I’ll transfer them to the server.
It works equally fine in WSL or WSL2 on Windows.&lt;/p&gt;

&lt;p&gt;In case you haven’t installed anything yet:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apt update &amp;amp;&amp;amp; sudo apt install openssl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, prepare the config files and directory layout:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir ~/keys
$ cd ~/keys
$ mkdir -p ca/root-ca/private ca/root-ca/db crl certs etc
$ chmod 700 ca/root-ca/private
$ touch etc/root-ca.conf etc/tls-ca.conf etc/tls-server.conf etc/tls-client.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;File &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etc/root-ca.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# ACME Root CA

[ default ]
ca                      = root-ca                   # CA name
dir                     = .                         # Top dir
base_url                = http://www.acme.com/ca    # CA base URL
aia_url                 = $base_url/$ca.cer         # CA certificate URL
crl_url                 = $base_url/$ca.crl         # CRL distribution point
name_opt                = multiline,-esc_msb,utf8   # Display UTF-8 characters

# CA certificate request

[ req ]
default_bits            = 4096                  # RSA key size
encrypt_key             = yes                   # Protect private key
default_md              = sha256                # MD to use
utf8                    = yes                   # Input is UTF-8
string_mask             = utf8only              # Emit UTF-8 strings
prompt                  = no                    # Don&apos;t prompt for DN
distinguished_name      = ca_dn                 # DN section
req_extensions          = ca_reqext             # Desired extensions

[ ca_dn ]
countryName             = &quot;US&quot;
organizationName        = &quot;Acme&quot;
organizationalUnitName  = &quot;Acme Certificate Authority&quot;
commonName              = &quot;Acme Root CA&quot;

[ ca_reqext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true
subjectKeyIdentifier    = hash

# CA operational settings

[ ca ]
default_ca              = root_ca               # The default CA section

[ root_ca ]
certificate             = $dir/ca/$ca.crt       # The CA cert
private_key             = $dir/ca/$ca/private/$ca.key # CA private key
new_certs_dir           = $dir/ca/$ca           # Certificate archive
serial                  = $dir/ca/$ca/db/$ca.crt.srl # Serial number file
crlnumber               = $dir/ca/$ca/db/$ca.crl.srl # CRL number file
database                = $dir/ca/$ca/db/$ca.db # Index file
unique_subject          = no                    # Require unique subject
default_days            = 3652                  # How long to certify for
default_md              = sha256                # MD to use
policy                  = match_pol             # Default naming policy
email_in_dn             = no                    # Add email to cert DN
preserve                = no                    # Keep passed DN ordering
name_opt                = $name_opt             # Subject DN display options
cert_opt                = ca_default            # Certificate display options
copy_extensions         = none                  # Copy extensions from CSR
x509_extensions         = signing_ca_ext        # Default cert extensions
default_crl_days        = 365                   # How long before next CRL
crl_extensions          = crl_ext               # CRL extensions

[ match_pol ]
countryName             = match                 # Must match &apos;US&apos;
stateOrProvinceName     = optional              # Included if present
localityName            = optional              # Included if present
organizationName        = match                 # Must match &apos;Acme&apos;
organizationalUnitName  = supplied              # Must be present
commonName              = supplied              # Must be present

[ any_pol ]
domainComponent         = optional
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = optional
emailAddress            = optional

# Extensions

[ root_ca_ext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always

[ signing_ca_ext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true,pathlen:0
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = $aia_url

[ crl_info ]
URI.0                   = $crl_url
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etc/tls-ca.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Acme TLS CA

[ default ]
ca                      = tls-ca                # CA name
dir                     = .                     # Top dir
base_url                = http://www.acme.com/ca    # CA base URL
aia_url                 = $base_url/$ca.cer     # CA certificate URL
crl_url                 = $base_url/$ca.crl     # CRL distribution point
name_opt                = multiline,-esc_msb,utf8 # Display UTF-8 characters

# CA certificate request

[ req ]
default_bits            = 4096                  # RSA key size
encrypt_key             = yes                   # Protect private key
default_md              = sha256                # MD to use
utf8                    = yes                   # Input is UTF-8
string_mask             = utf8only              # Emit UTF-8 strings
prompt                  = no                    # Don&apos;t prompt for DN
distinguished_name      = ca_dn                 # DN section
req_extensions          = ca_reqext             # Desired extensions

[ ca_dn ]
countryName             = &quot;US&quot;
organizationName        = &quot;Acme&quot;
organizationalUnitName  = &quot;Acme Certificate Authority&quot;
commonName              = &quot;Acme TLS CA&quot;

[ ca_reqext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true,pathlen:0
subjectKeyIdentifier    = hash

# CA operational settings

[ ca ]
default_ca              = tls_ca                # The default CA section

[ tls_ca ]
certificate             = $dir/ca/$ca.crt       # The CA cert
private_key             = $dir/ca/$ca/private/$ca.key # CA private key
new_certs_dir           = $dir/ca/$ca           # Certificate archive
serial                  = $dir/ca/$ca/db/$ca.crt.srl # Serial number file
crlnumber               = $dir/ca/$ca/db/$ca.crl.srl # CRL number file
database                = $dir/ca/$ca/db/$ca.db # Index file
unique_subject          = no                    # Require unique subject
default_days            = 730                   # How long to certify for
default_md              = sha256                # MD to use
policy                  = match_pol             # Default naming policy
email_in_dn             = no                    # Add email to cert DN
preserve                = no                    # Keep passed DN ordering
name_opt                = $name_opt             # Subject DN display options
cert_opt                = ca_default            # Certificate display options
copy_extensions         = copy                  # Copy extensions from CSR
x509_extensions         = server_ext            # Default cert extensions
default_crl_days        = 1                     # How long before next CRL
crl_extensions          = crl_ext               # CRL extensions

[ match_pol ]
countryName             = match                 # Must match &apos;US&apos;
stateOrProvinceName     = optional              # Included if present
localityName            = optional              # Included if present
organizationName        = match                 # Must match &apos;Acme&apos;
organizationalUnitName  = supplied              # Must be present
commonName              = supplied              # Must be present

[ extern_pol ]
countryName             = supplied              # Must be present
stateOrProvinceName     = optional              # Included if present
localityName            = optional              # Included if present
organizationName        = supplied              # Must be present
organizationalUnitName  = supplied              # Must be present
commonName              = supplied              # Must be present

[ any_pol ]
domainComponent         = optional
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = optional
emailAddress            = optional

# Extensions

[ server_ext ]
keyUsage                = critical,digitalSignature,keyEncipherment
basicConstraints        = CA:false
extendedKeyUsage        = serverAuth,clientAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ client_ext ]
keyUsage                = critical,digitalSignature
basicConstraints        = CA:false
extendedKeyUsage        = clientAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = $aia_url

[ crl_info ]
URI.0                   = $crl_url
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etc/tls-server.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# TLS server certificate request

[ default ]
SAN                     = DNS:acme.com      # Default value

[ req ]
default_bits            = 4096                  # RSA key size
encrypt_key             = no                    # Protect private key
default_md              = sha256                # MD to use
utf8                    = yes                   # Input is UTF-8
string_mask             = utf8only              # Emit UTF-8 strings
prompt                  = yes                   # Prompt for DN
distinguished_name      = server_dn             # DN template
req_extensions          = server_reqext         # Desired extensions

[ server_dn ]
countryName             = &quot;1. Country Name (2 letters) (eg, US)       &quot;
countryName_max         = 2
stateOrProvinceName     = &quot;2. State or Province Name   (eg, region)   &quot;
localityName            = &quot;3. Locality Name            (eg, city)     &quot;
organizationName        = &quot;4. Organization Name        (eg, company)  &quot;
organizationalUnitName  = &quot;5. Organizational Unit Name (eg, section)  &quot;
commonName              = &quot;6. Common Name              (eg, FQDN)     &quot;
commonName_max          = 64

[ server_reqext ]
keyUsage                = critical,digitalSignature,keyEncipherment
extendedKeyUsage        = serverAuth,clientAuth
subjectKeyIdentifier    = hash
subjectAltName          = $ENV::SAN
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etc/tls-client.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# TLS client certificate request

[ req ]
default_bits            = 4096                  # RSA key size
encrypt_key             = yes                   # Protect private key
default_md              = sha256                # MD to use
utf8                    = yes                   # Input is UTF-8
string_mask             = utf8only              # Emit UTF-8 strings
prompt                  = yes                   # Prompt for DN
distinguished_name      = client_dn             # DN template
req_extensions          = client_reqext         # Desired extensions

[ client_dn ]
countryName             = &quot;1. Country Name (2 letters) (eg, US)       &quot;
countryName_max         = 2
stateOrProvinceName     = &quot;2. State or Province Name   (eg, region)   &quot;
localityName            = &quot;3. Locality Name            (eg, city)     &quot;
organizationName        = &quot;4. Organization Name        (eg, company)  &quot;
organizationalUnitName  = &quot;5. Organizational Unit Name (eg, section)  &quot;
commonName              = &quot;6. Common Name              (eg, full name)&quot;
commonName_max          = 64
emailAddress            = &quot;7. Email Address            (eg, name@fqdn)&quot;
emailAddress_max        = 40

[ client_reqext ]
keyUsage                = critical,digitalSignature
extendedKeyUsage        = clientAuth
subjectKeyIdentifier    = hash
subjectAltName          = email:move
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setup-ca&quot;&gt;Setup CA&lt;/h2&gt;

&lt;p&gt;A certificate authority takes care of signing certificates and keeping track which certificates it has signed but also which ones it has revoked. We will set up this infrastructure.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cp /dev/null ca/root-ca/db/root-ca.db
$ cp /dev/null ca/root-ca/db/root-ca.db.attr
$ echo 01 &amp;gt; ca/root-ca/db/root-ca.crt.srl
$ echo 01 &amp;gt; ca/root-ca/db/root-ca.crl.srl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;create-a-ca-request&quot;&gt;Create a CA request&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ openssl req -new \
    -config etc/root-ca.conf \
    -out ca/root-ca.csr \
    -keyout ca/root-ca/private/root-ca.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When asked for a passphrase, enter your password. The command uses the info from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root-ca.conf&lt;/code&gt; file. The result is a private key and a CSR (certificate signing request).&lt;/p&gt;

&lt;h3 id=&quot;create-a-ca-certificate&quot;&gt;Create a CA certificate&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ openssl ca -selfsign \
    -config etc/root-ca.conf \
    -in ca/root-ca.csr \
    -out ca/root-ca.crt \
    -extensions root_ca_ext
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now have a self-signed root CA. This CA is the origin of trust in your public key infrastructure. To create “usable” certificates, you also need to have signing certificates. These are created in the next part. Notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-selfsign&lt;/code&gt; option.&lt;/p&gt;

&lt;h4 id=&quot;crl&quot;&gt;CRL&lt;/h4&gt;

&lt;p&gt;The root CA can also revoke certificates. Hence we have to create the certificate revoke list.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ openssl ca -gencrl \
    -config etc/root-ca.conf \
    -out crl/root-ca.crl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;create-tls-server-ca&quot;&gt;Create TLS server CA&lt;/h3&gt;

&lt;p&gt;The TLS-server CA is an intermediate certificate that will be used to sign all TLS certificates. If that doesn’t make sense think of this: Would the president sign all the passports of his citizens by himself? Probably not. The president does however grant certain people the right to sign on his behalf. That’s what we’re also doing by creating a TLS server CA.&lt;/p&gt;

&lt;p&gt;First, create the directories to store the files.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir -p ca/tls-ca/private ca/tls-ca/db
$ chmod 700 ca/tls-ca/private
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the database:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cp /dev/null ca/tls-ca/db/tls-ca.db
$ cp /dev/null ca/tls-ca/db/tls-ca.db.attr
$ echo 01 &amp;gt; ca/tls-ca/db/tls-ca.crt.srl
$ echo 01 &amp;gt; ca/tls-ca/db/tls-ca.crl.srl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;create-a-ca-request-1&quot;&gt;Create a CA request&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ openssl req -new \
    -config etc/tls-ca.conf \
    -out ca/tls-ca.csr \
    -keyout ca/tls-ca/private/tls-ca.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a regular CA, this creates the private key and a CSR. Also, give the key a password to protect from unauthorized use.&lt;/p&gt;

&lt;h3 id=&quot;create-ca&quot;&gt;Create CA&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ openssl ca \
    -config etc/root-ca.conf \
    -in ca/tls-ca.csr \
    -out ca/tls-ca.crt \
    -extensions signing_ca_ext
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The root CA validates and signs the request, creating the TLS server CA.&lt;/p&gt;

&lt;p&gt;It all starts coming together when looking at the parameters for the command: We create a ca (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl ca -out ca/tls-ca.crt&lt;/code&gt;) using the CRS (-in ca/tls-ca.csr). The outcome is a signing CA (-extension signing_ca_ext). Mind that we here use the root CA’s config file. After all, the request was made by the TLS server CA’s config and now the work has to be done by the root.&lt;/p&gt;

&lt;h4 id=&quot;crl-1&quot;&gt;CRL&lt;/h4&gt;

&lt;p&gt;Also here, create a certificate revoke list.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl ca -gencrl \
    -config etc/tls-ca.conf \
    -out crl/tls-ca.crl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;pem-bundle&quot;&gt;PEM bundle&lt;/h4&gt;

&lt;p&gt;The PEM bundle is a certificate chain.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cat ca/tls-ca.crt ca/root-ca.crt &amp;gt; \
    ca/tls-ca-chain.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you look at the contents of the file, it is nothing more than the root certificate and the tls-server certificate pasted after each other.&lt;/p&gt;

&lt;h2 id=&quot;issuing-certificates&quot;&gt;Issuing certificates&lt;/h2&gt;

&lt;p&gt;Our infrastructure is ready to create certificates that will be deployed to our servers.&lt;/p&gt;

&lt;p&gt;Let’s create a certificate for our Cockpit control panel. The control panel is reachable on “cpanel.acme.com”&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Our infrastructure is completely ready now. When we want to have a certificate for one of our services we create a request and the authority signs it. Think of it like these real-world analogies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;bank notes backed up by a central bank&lt;/li&gt;
  &lt;li&gt;passports signed by a country’s representative&lt;/li&gt;
  &lt;li&gt;contracts notarized by a notary&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;create-a-tls-server-request&quot;&gt;Create a TLS server request&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ SAN=DNS:cpanel.acme.com \
openssl req -new \
    -config etc/tls-server.conf \
    -out certs/cpanel.acme.com.csr \
    -keyout certs/cpanel.acme.com.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mind the environment variable we set first. We also don’t set a passphrase.&lt;/p&gt;

&lt;h3 id=&quot;create-the-tls-certificate&quot;&gt;Create the TLS certificate&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ openssl ca \
    -config etc/tls-ca.conf \
    -in certs/cpanel.acme.com.csr \
    -out certs/cpanel.acme.com.crt \
    -extensions server_ext
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If this is your first certificate, a copy will be stored under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ca/tls-ca/01.pem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Which files do you need in your actual service?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;tls-ca.crt: the public root certificate as the basis of trust&lt;/li&gt;
  &lt;li&gt;cpanel.acme.com.crt: the public server certificate which has the FQDN incorporated&lt;/li&gt;
  &lt;li&gt;cpanel.acme.com.key: the private key to be able to decrypt&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;copy-to-cockpit&quot;&gt;Copy to cockpit&lt;/h4&gt;

&lt;p&gt;Cockpit &lt;a href=&quot;https://cockpit-project.org/guide/228/https.html&quot;&gt;requires&lt;/a&gt; to have the server certificate and the intermediate certificate in the same file.
Although not mentioned in the docs, I also had to copy the private key into the same file to get it working. Also, notice the file extension change 
when moving the certificate chain to Cockpit: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.crt&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cert&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cat certs/cpanel.acme.com.crt ca/tls-ca.crt certs/cpanel.acme.com.key &amp;gt; certs/cpanel.acme.com-chain.crt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Copy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certs/cpanel.acme.com-chain.cert&lt;/code&gt; to your server and place it in Cockpit’s config directory.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo mv cpanel.acme.com-chain.crt /etc/cockpit/ws-certs.d/cpanel.acme.com.cert
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Give the files the proper ownership and permissions:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo chown root:cockpit-ws /etc/cockpit/ws-certs.d/cpanel.acme.com.cert
$ sudo chmod 640 /etc/cockpit/ws-certs.d/cpanel.acme.com.cert
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;revoking-certificates&quot;&gt;Revoking certificates&lt;/h2&gt;

&lt;p&gt;Should you want to revoke a certificate (the private key has been compromised) before its expiration date, you can add it to the CRL (certificate revoke list). You have to know the id-number of the certificate though. If you didn’t remember, look into the signing-db: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/keys/ca/signing-ca/db/signing-ca.db&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;revoke-a-certificate&quot;&gt;Revoke a certificate&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl ca \
    -config etc/signing-ca.conf \
    -revoke ca/signing-ca/01.pem \
    -crl_reason superseded
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The compromised certificate is marked ‘revoked’ and will be included in new CRLs the CA issues.&lt;/p&gt;

&lt;h3 id=&quot;create-a-crl&quot;&gt;Create a CRL&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl ca -gencrl \
    -config etc/signing-ca.conf \
    -out crl/signing-ca.crl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;adding-your-own-certificates-your-system&quot;&gt;Adding your own certificates your system&lt;/h2&gt;

&lt;p&gt;You’ve set up your own public key infrastructure and certificate authority. However, your browser (and other programs) doesn’t know about this.&lt;/p&gt;

&lt;p&gt;To have your computer trust the root certificate, copy it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/share/ca-certificates/&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo cp ~/keys/ca/root-ca.crt /usr/local/share/ca-certificates/
$ sudo update-ca-certificates
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you use Firefox as I do, you will notice that your cockpit login page still shows a warning. Firefox does not take your system’s certificates as a trusted store. To solve this, head over to &lt;a href=&quot;/posts/2-Firefox-and-self-signed-certificates&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll then have this screen:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/certman/cockpit.jpg&quot; alt=&quot;trusted cockpit&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It still says the certificate is not trusted by Mozilla, but since you trust it Firefox won’t make a fuss about it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;small&gt;Lock photo by &lt;a href=&quot;https://pixabay.com/users/pasja1000-6355831/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3745490&quot;&gt;pasja1000&lt;/a&gt; from &lt;a href=&quot;https://pixabay.com/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=3745490&quot;&gt;Pixabay&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;The control panel is only reachable from the LAN. Its domain name is defined in the router’s dnsmasq service. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 21 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Certificate-management</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Certificate-management</guid>
        
        <category>OpenSSL</category>
        
        <category>self-signed</category>
        
        <category>certificates</category>
        
        
      </item>
    
      <item>
        <title>Eaton UPS monitoring</title>
        <description>&lt;p&gt;Power outages are rare nowadays. But they are not nonexistent. I bought a second-hand UPS and a new battery to keep my server up during an eventual short outage.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;So I bought a second-hand Eaton Ellipse ASR 750. It’s a rather old device but it came with a new battery. And it has a USB connection so I plugged it into my server and started with &lt;a href=&quot;https://networkupstools.org/&quot;&gt;Network UPS tools&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Network UPS Tools or NUT has been around for ages, so it made its way into the standard Debian repositories.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apt install nut
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This installs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bash-completion libupsclient4 nut-client nut-server&lt;/code&gt;. Your machine may yield different results.&lt;/p&gt;

&lt;p&gt;There were some error messages. We’ll take care of them later:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Created symlink /etc/systemd/system/multi-user.target.wants/nut-monitor.service → /lib/systemd/system/nut-monitor.service.
Job for nut-monitor.service failed because the service did not take the steps required by its unit configuration.
See &quot;systemctl status nut-monitor.service&quot; and &quot;journalctl -xe&quot; for details.
invoke-rc.d: initscript nut-client, action &quot;start&quot; failed.
● nut-monitor.service - Network UPS Tools - power device monitor and shutdown controller
   Loaded: loaded (/lib/systemd/system/nut-monitor.service; enabled; vendor preset: enabled)
   Active: failed (Result: protocol) since Mon 2021-04-19 20:34:41 CEST; 10ms ago
  Process: 31660 ExecStart=/sbin/upsmon (code=exited, status=0/SUCCESS)
      CPU: 2ms

Apr 19 20:34:41 server systemd[1]: Starting Network UPS Tools - power device monitor and shutdown controller...
Apr 19 20:34:41 server upsmon[31660]: upsmon disabled, please adjust the configuration to your needs
Apr 19 20:34:41 server upsmon[31660]: Then set MODE to a suitable value in /etc/nut/nut.conf to enable it
Apr 19 20:34:41 server systemd[1]: nut-monitor.service: Can&apos;t open PID file /run/nut/upsmon.pid (yet?) after start: No such file or directory
Apr 19 20:34:41 server systemd[1]: nut-monitor.service: Failed with result &apos;protocol&apos;.
Apr 19 20:34:41 server systemd[1]: Failed to start Network UPS Tools - power device monitor and shutdown controller.
Apr 19 20:34:41 server systemd[1]: nut-monitor.service: Consumed 2ms CPU time.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now check if the UPS is connected and recognized:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ lsusb | grep UPS
Bus 001 Device 002: ID 0463:ffff MGE UPS Systems UPS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Bingo!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Vendor ID: 0463&lt;/li&gt;
  &lt;li&gt;Device ID: ffff&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;We will now set up &lt;em&gt;nut&lt;/em&gt; to check on the UPS.&lt;/p&gt;

&lt;p&gt;In the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nut/ups.conf&lt;/code&gt; we add the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[eaton]
driver = usbhid-ups
port = auto
desc = &quot;Eaton Ellipse ASR 750&quot;
synchronous = &quot;yes&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s test&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# this doesn&apos;t work
$ upsdrvctl start
-bash: upsdrvctl: command not found
# should be somewhere...
$ whereis upsdrvctl
upsdrvctl: /usr/sbin/upsdrvctl /usr/share/man/man8/upsdrvctl.8.gz
$ /usr/sbin/upsdrvctl start
Network UPS Tools - UPS driver controller 2.7.4
Can&apos;t open /etc/nut/ups.conf: Can&apos;t open /etc/nut/ups.conf: Permission denied
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;My UPS only has one “consumer”, which is my server. So NUT can perfectly be set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;standalone&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;In the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nut/nut.conf&lt;/code&gt; set:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
MODE=standalone
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the driver configured, there are two services left: &lt;strong&gt;upsd&lt;/strong&gt; and &lt;strong&gt;upsmon&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;upsd&lt;/strong&gt;, or the daemon will serve the UPS data to the clients and is listening on localhost, port 3493.&lt;/p&gt;

&lt;p&gt;In the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nut/uspd.conf&lt;/code&gt; set:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
# comment out this line:
LISTEN 127.0.0.1 3493
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;upsmon&lt;/strong&gt; interacts with upsd it’s configuration is two-fold: access.&lt;/p&gt;

&lt;p&gt;In the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nut/upsd.users&lt;/code&gt; set:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[upsmonitor]
password = ups_password
upsmon master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The daemon is listening and knows who to allow access. So now configure the monitor.&lt;/p&gt;

&lt;p&gt;In the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nut/upsmon.conf&lt;/code&gt; add:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MONITOR eaton@localhost 1 upsmonitor ups_password master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;test&quot;&gt;Test&lt;/h2&gt;

&lt;p&gt;You could simply pull the plug. But first, make sure all services are running correctly!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo systemctl start ups-driver
$ sudo systemctl start nut-server
$ sudo systemctl start ups-monitor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A reboot may work too because the services are marked for auto-start.&lt;/p&gt;

&lt;p&gt;You can check the installation with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ upsc eaton@localhost
battery.charge: 100
battery.charge.low: 30
battery.runtime: 3000
battery.type: PbAc
device.mfr: EATON
device.model: Ellipse 750
device.serial: BDCL440GL
device.type: ups
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: yes
driver.version: 2.7.4
driver.version.data: MGE HID 1.39
driver.version.internal: 0.41
input.transfer.high: 264
input.transfer.low: 184
outlet.1.desc: PowerShare Outlet 1
outlet.1.id: 2
outlet.1.status: on
outlet.1.switchable: no
outlet.desc: Main Outlet
outlet.id: 1
outlet.switchable: no
output.frequency.nominal: 50
output.voltage: 230.0
output.voltage.nominal: 230
ups.beeper.status: enabled
ups.delay.shutdown: 20
ups.delay.start: 30
ups.load: 2
ups.mfr: EATON
ups.model: Ellipse 750
ups.power.nominal: 750
ups.productid: ffff
ups.serial: BDCL440GL
ups.status: OL
ups.timer.shutdown: -1
ups.timer.start: -10
ups.vendorid: 0463
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;connection-refused&quot;&gt;Connection refused?&lt;/h3&gt;

&lt;p&gt;NUT runs as &lt;em&gt;nut&lt;/em&gt; user and has no access to USB by default. So we have to create udev-rules to solve this.&lt;/p&gt;

&lt;p&gt;Create a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/udev/rules.d/90-nut-ups.rules&lt;/code&gt; with the following content. Mind the idVendor and idProduct we discovered in the first step.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Eaton ellipse ASR 750
ACTION==&quot;add&quot;, SUBSYSTEM==&quot;usb&quot;, ATTR{idVendor}==&quot;0463&quot;, ATTR{idProduct}==&quot;ffff&quot;, MODE=&quot;0660&quot;, GROUP=&quot;nut&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-ups-is-gone&quot;&gt;The UPS is gone?&lt;/h3&gt;

&lt;p&gt;Sometimes the UPS driver fails and loses connection. That would be disastrous. After all, knowing how the UPS is doing is crucial for a gracious shutdown should the battery get low.&lt;/p&gt;

&lt;p&gt;You can find out with this command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ /bin/upsc eaton | grep &apos;device.type&apos;
Init SSL without certificate database
Error: Data stale
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Data stale? Then reload the driver. While we could restart the basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo /lib/nut/usbhid-ups -a eaton&lt;/code&gt; this doesn’t help when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nut-driver&lt;/code&gt; service already failed. So we restart the service and the service will take care of restarting the underlying driver.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo systemctl restart nut-driver
Network UPS Tools - UPS driver controller (2.7.4)
USB communication driver 0.33
Network UPS Tools - Generic HID driver 0.41 (2.7.4)
Using subdriver: MGE HID 1.39
Duplicate driver instance detected! Terminating other driver!

# Now check again
$ /bin/upsc eaton | grep &apos;device.type&apos;
Init SSL without certificate database
device.type: ups
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Best to put this in a script and run it regularly.&lt;/p&gt;

&lt;p&gt;Create a file ~/checkups.sh&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/bin/bash

if [[ $(/bin/upsc eaton | grep &apos;device.type&apos;) == *ups ]]; then
  exit 0
else
  systemctl restart nut-driver
fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The frequency to run this script depends on the size of the UPS and the power of your server. The power source of my server is rated 80W. The UPS is 750VA or 450W with a 12V/9Ah battery. The battery can deliver about 108VAh. On maximum load, it should theoretically last about one hour. So a safe interval of checking every 10 minutes should be more than enough. There is one thing we have to take care of though. The default value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;upsmon.conf&lt;/code&gt; makes &lt;em&gt;upsmon&lt;/em&gt; check the UPS every 5 seconds. When a UPS isn’t answering to the polls, it is marked “stale”. When this condition lasts for more than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEADTIME&lt;/code&gt;, the UPS is marked “dead”.&lt;/p&gt;

&lt;p&gt;I chose a checking frequency of 60 seconds while on AC power and 10 seconds while on battery power.&lt;/p&gt;

&lt;p&gt;Since we only check the USB connection every 10 minutes but poll every minute, or 10 seconds depending on the power source, we should set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEADTIME&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NOCOMMWARNTIME&lt;/code&gt; to 600 seconds. This will avoid spamming the log when the USB connection to the UPS goes down.&lt;/p&gt;

&lt;p&gt;In file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nut/upsmon.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POLLFREQ 60
POLLFREQALERT 10
DEADTIME 600
NOCOMMWARNTIME 600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While we could use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd&lt;/code&gt; for this, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crontab&lt;/code&gt; is more straightforward and equally reliable.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cron&lt;/code&gt; is running out of the box on Debian 10 but it doesn’t hurt to check:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo systemctl start cron
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2021-04-12 17:44:11 CEST; 2 days ago
     Docs: man:cron(8)
 Main PID: 412 (cron)
    Tasks: 2 (limit: 4915)
   Memory: 190.7M
      CPU: 1min 58.452s
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The script has to run as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; since we don’t want to be asked for our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; password when we’re low on power. So use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ sudo crontab -e&lt;/code&gt; instead of your user’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ crontab -e&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo crontab -e

# add in the following
# the script will run every half hour, 5 past the hour and at 35 past
5,35 * * * * /home/&amp;lt;username&amp;gt;/checkups.sh 2&amp;gt;&amp;amp;1 | /usr/bin/logger -t checkups

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I stop worrying about ungraceful shutdowns because of power outages.&lt;/p&gt;

&lt;h2 id=&quot;live-test&quot;&gt;Live test&lt;/h2&gt;

&lt;p&gt;I did a live test by pulling the plug on the UPS and checked the UPS’s parameters a few times.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ upsc eaton@localhost | grep &apos;battery&apos;
Init SSL without certificate database
battery.charge: 91
battery.charge.low: 30
battery.runtime: 2730
battery.type: PbAc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;“I love it when a plan comes together.” &lt;cite&gt;- Colonel John “Hannibal” Smith -&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;small&gt;Power meter photo by &lt;a href=&quot;https://unsplash.com/@tanerardali?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;taner ardalı&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/power-meter?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 13 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://www.emelis.net/posts/1-Eaton-UPS-monitoring</link>
        <guid isPermaLink="true">https://www.emelis.net/posts/1-Eaton-UPS-monitoring</guid>
        
        <category>Debian</category>
        
        <category>UPS</category>
        
        <category>networkupstools</category>
        
        
      </item>
    
  </channel>
</rss>
