Blog

  • Install Traefik Proxy on Debian.

    This post is intended to cover how to install the Traefik Proxy on a Debian server. The process is a little complex as, unfortunately, there isn’t a .deb file that I could find.

    This means a bit more manual fiddling about.

    Logo for Traefik Proxy

    First off, some of the steps here come from this blog:
    https://blog.emka.web.id/2022/09/how-to-install-traefik-in-debian.html
    and the Traefik site:
    https://doc.traefik.io/traefik/getting-started/install-traefik/#use-the-binary-distribution

    I’ve adjusted the steps to cover my own needs.

    Preparation

    The installation of Traefik proxy on Debian requires some setup task.

    Create a group for Traefik – obviously check the group ID is unique.

    sudo groupadd -g 321 traefik

    Then a user – obviously check the group ID is unique:

    sudo useradd \
     -g traefik --no-user-group \
     --home-dir /var/www --no-create-home \
     --shell /usr/sbin/nologin \
     --system --uid 321 traefik

    Create necessary directories for the software.

    mkdir /opt/traefik
    mkdir /etc/traefik
    mkdir /var/opt/traefik

    I’m not fiddling about with directory permissions yet – as I am trying to avoid having to run everything through sudo.

    Now download a copy of Traefik Proxy software. That’s done by getting an appropriate file from here:
    https://github.com/traefik/traefik/releases

    Finally fetch a copy of the service file from here:
    https://github.com/traefik/traefik/raw/master/contrib/systemd/traefik.service

    Install

    Install Traefik Proxy Service

    Update the traefik.service file:

    vi traefik.service

    Removed the comments from:

    • Within [Unit]
      • After
      • AssertFileIsExecutable
        Fixing the path to the executable.
      • AssertPathExists
        Fixing the file to be traefik.yaml
    • Within [Service]
      • User
      • AmbientCapabilities
      • ExecStart
        Fixing the executable path and making the configFile parameter point to traefik.yaml file.

    Then transfer the service file to the correct location:

    sudo mv traefik.service /etc/system/system/
    sudo chown root: root /etc/systemd/system/traefik.service
    sudo chmod 644 /etc/systemd/system/traefik.service

    Then update systemd:

    systemctl daemon-reload

    This will not be use under a functional configuration is in place.

    Starter Configuration

    Static Configuration

    Now copy the below starter configuration and place it in /etc/traefik/traefik.yaml

    ################################################################
    #
    # Configuration sample for Traefik v2.
    #
    # For Traefik v1: 
    # https://github.com/traefik/traefik/blob/v1.7/traefik.sample.toml
    #
    ################################################################
    
    ################################################################
    # Global configuration
    ################################################################
    global:
      checkNewVersion: true
      sendAnonymousUsage: true
    ################################################################
    # EntryPoints configuration
    ################################################################
    entryPoints:
      web:
        address: :85
      websecure:
        address: :448
    ################################################################
    # Traefik logs configuration
    ################################################################
    log:
      level: DEBUG
    ################################################################
    # API and dashboard configuration
    ################################################################
    # Enable API and dashboard
    api:
      dashboard: true
    
    providers:
      file:
        filename: /etc/traefik/dynamic.yaml

    In short, this file will:

    • Make traefik listen on port 85 and 448
    • Increase logging to debug level
      So, we can see what is going on
    • Enable the API and the Dashboard
    • Configure a file provider call dynamic.yaml

    Dynamic Configuration

    Now create an authentication user (replace the content of the angle brackets) – you will need the output from this in the next step.

    htpasswd -nb <user> <password>

    Follow this up with placing this in /etc/traefik/dynamic.yaml replacing <string from htpasswd> with your string from htpasswd (yes, put it inside the double quotes).

    # dynamic.yaml
    
    http:
      routers:
        api:
          rule: PathPrefix(`/api`) || PathPrefix(`/dashboard`)
          service: api@internal
          entryPoints:
            - "web"
          middlewares:
            - auth
        catchall:
          # attached only to web entryPoint
          entryPoints:
            - "web"
          # catchall rule
          rule: "PathPrefix(`/`)"
          service: unavailable
          # lowest possible priority
          # evaluated when no other router is matched
          priority: 1
      middlewares:
        auth:
          basicAuth:
            users:
              - "<string from htpasswd>"
      services:
        # Service that will always answer a 503 Service Unavailable response
        unavailable:
          loadBalancer:
            servers: {}

    Yes, the back ticks are correct, single quote will cause a problem due to go.

    This file sets up the following:

    • Two routers
      1. API
        • catch traffic coming in from the “web” entry point (85)
        • protects using the auth middleware
        • looks for /api and /dashboard traffic
        • will then route trafic to api@internal service
      2. CatchAll
        • catch traffic coming in from the “web” entry point (85)
        • looks for anything under /
        • will route traffic to unavailable service.
    • Middleware
      To protect the api and dashboard endpoints from prying eyes.
    • Service
      To show when things are broken.

    Install Traefik Proxy

    The next step of the install of Traefik Proxy on Debian is to extract the downloaded zip file:

    cd /opt/traefik
    tar -zxvf <download location>/traefik_v<version>_<platform>.tar.gz

    Since traefik proxy will be using privileged ports, it therefore needs a permission setting:

    sudo setcap 'cap_net_bind_service=+ep' traefik

    Testing Traefik Proxy

    This is where things begin to get fun. I had some fun and games with getting the Dashboard to work initially, hence why I am writing this and posting it for posterity.

    You MUST have the PathPrefix rule to make Dashboard and API endpoints work right.

    On the plus side, its presence in dynamic.yaml means we can fiddle about with the file and Traefik Proxy will just reload it.

    Now, simply run the Traefik Proxy executable – it looks in standard locations for configuration and /etc/traefik/traefik.yaml is one of those.

    ./traefik

    If it works you should see something like this:

    
    
    
    
    

    You should also be able to access various URLs.

    api/endpoints

    dashboard

    anything else

    Assuming everything is working we can now go about locking the software installation, enabling the services configuration that was setup, and linking it to the Docker.

    Troubleshooting

    Hopefully, Traefic Proxy is working for you. If it isn’t the terminal that Traefic is running in should give you some indication of what has gone wrong.

    It is likely to be related to listening on the selected ports. The simplest option would then be to move to a different port by altering the values for address in /etc/traefik/traefik.yaml.

    Having done this, stop traefik [if needed] and re-run it.

  • Custom PHP Container

    Custom PHP Container

    As part of the creation of my new lab installation I wanted to migrate WordPress from barebones Apache/FPM into a custom PHP container.

    The original thought was to segretate the web server and PHP FPM from one another – but it seemed to be far to complex. I eventually found this web site:

    Containerize a PHP Application

    This site is talking about a generalised solution for embedding any PHP application into a container, but it turns out the approach worked fine for WordPress too.

    In short, it is easier to start off with a PHP-FPM container. So I chose one from the DockerHub PHP site.

    Having done that, I created a Docker file:

    # Dockerfile.nginx - PHP-FPM with Nginx in a single container
    FROM php:8.3-fpm-alpine
    
    # Install Nginx
    RUN apk add --no-cache nginx curl
    
    # Install PHP extensions
    RUN apk add --no-cache \
        freetype-dev \
        libjpeg-turbo-dev \
        libpng-dev \
        libzip-dev \
        icu-dev \
        postgresql-dev \
        && docker-php-ext-configure gd --with-freetype --with-jpeg \
        && docker-php-ext-install -j$(nproc) \
            gd zip intl pdo pdo_mysql pdo_pgsql opcache
    
    # PHP-FPM configuration
    COPY php-fpm.conf /usr/local/etc/php-fpm.d/www.conf
    COPY php-production.ini /usr/local/etc/php/conf.d/production.ini
    
    # Nginx configuration
    COPY nginx.conf /etc/nginx/nginx.conf
    COPY nginx-default.conf /etc/nginx/http.d/default.conf
    
    # Copy application code
    COPY . /var/www/html/
    RUN chown -R www-data:www-data /var/www/html
    
    # Startup script that runs both Nginx and PHP-FPM
    COPY docker-entrypoint.sh /docker-entrypoint.sh
    RUN chmod +x /docker-entrypoint.sh
    
    EXPOSE 80
    
    HEALTHCHECK --interval=15s --timeout=5s --retries=3 \
      CMD curl -f http://localhost/health.php || exit 1
    
    ENTRYPOINT ["/docker-entrypoint.sh"]

    This file:

    • Installs NGINX
    • Configures NGINX
    • Installs PHP modules.
    • Configures FPM
    • Installs CURL
    • Defines a CURL healthcheck
    • Mounts the application and fixes the permissions.

    TODO: add actual example files.

    I then just archived my installation on the old server, and transferred the directories to the Lab server. These where then mounted as volumes.

    Obviously, I need to do regular checks of the image to make sure it is patched up – but WordPress is working in my custom PHP container (as you can tell by being here now!)

  • HAOS SSH

    HAOS SSH

    I’ve recently reinstalled my HomeAssistant using HAOS, rather than my previous Supervisor install – mainly because the suppliers of HomeAssistant have desupported that method. However, I still want to be able to connect at the operating system level, rather than only relying on HomeAssistant WebUI for everything – and that means getting HAOS SSH mode working.

    I initially attempted to follow the “USB Method” documented here:

    HAOS Developer debugging

    However, it didn’t seem to want to work – even though the command appear to complete correctly. And I obviously couldn’t see if it was working, as I don’t have access to the operating system to check!

    I eventually found an alternative approach here:

    AlexxIT: Howto SSH to HassOS

    This lists the following steps (which I am repeating in case the source vanishes):

    1. Install the Advanced SSH & Web Terminal addon
      • Add your ssh key(s) to the addons configuration.
      • Disable addon Protection mode option
    2. Open addon Web UI and run the following:
      cp /etc/ssh/authorized_keys /share
      docker run -it --rm \
      -v /root:/mnt/root \
      -v /mnt/data/supervisor/share:/mnt/share \
      bash cp /mnt/share/authorized_keys /mnt/root/.ssh
      rm /share/authorized_keys
      ha host reboot
    3. HomeAssistant will now reboot (the final command told it to).
    4. That’s all. You should be able to access HAOS using ssh and the same keys on:
      • Port 22 – addon
      • Port 22222 – hassio host

      • Configure Postfix

        Configure Postfix

        My Lab server needs to be able to send emails now. I’ve done some digging about, and have decided that I will configure Postfix to do forward things to my email hosting provider instead of exim4.

        Obviously, this required a bit more thumping this time, as I’ve never used Postfix before.

        Annoyingly, the default that Debian sets up results in warning being generated in log files, which means you have to manually tune the main.cf file to make the warning go away and then I could configure it to forward to my email host.

        These initial changes involve me adding the following:

        default_cache_db_type = lmdb
        default_database_type = lmdb

        And then changing the following to refer to lmdb:

        alias_maps
        alias_database
        smtp_tls_session_cache_database

        With appropriate runs of postmap and postalias.

        Remember to delete the old .db files that Postfix will have created initially.

        Having completed this, I added the configuration to talk to my mail hosts server. This has come from the following sites:

        This largely now consists of:

        relayhost = [<fq hostname>]:<port>
        
        # SASL authentication for the relay
        smtp_sasl_auth_enable = yes
        smtp_sasl_password_maps = lmdb:/etc/postfix/sasl_passwd
        smtp_sasl_security_options = noanonymous
        smtp_sasl_tls_security_options = noanonymous

        Create the /etc/postfix/sasl_passwd file. The template for that is:

        [<fq hostname>]:<port> <username>:<password>

        Then fix the file permission to be rw only to the root user. Update the database version of the password file:

        postmap /etc/postfix/sasl_passwd

        And then restart Postfix:

        postfix reload

        Using sudo as required for both these commands.

        Then test you can send an email:

        sendmail <test address> <<EOF
        Subject: Test Email Send
        
        Email Content Line 1
        Email Content Line 2
        EOF

        Hopefully, if you look in the /var/log/mail.log you should be able to see an email being sent.

        The Postfix configure is complete if the log is correct and you receive the email.

      • Transfer Nginx Proxy Manager to a new server.

        Transfer Nginx Proxy Manager to a new server.

        As part of setting up my new lab server, I needed to transfer Nginx Proxy Manager from its old home to a new home. This is intended to capture what I did, in case I ever need to repeat the process.

        1. Backup npm_data/_data and npm_letsencrypt/_data locations on the old host.
        2. Migrate the stack from the old host to the new host using Portainer.
        3. Stop the new stack
          • It will create an empty installation, which is obviously not useful for me.
        4. Restore the backup of the stack volumes, replacing the ones the migration just created.
        5. Restart the stack,

        The transfer of Nginx Proxy Manager is now complete. Check that it has connectivity to the downstream servers, and then move any firewall rules so that it is now the external server rather than the old one.

        Obviously now clean up the old installation on the old docker server.

      • Using Home Assistant with a Proxy

        Using Home Assistant with a Proxy

        I use Nginx Proxy Manager to direct things around my URLs and web sites – including Home Assistant.

        Its a great product, but does mean I have to configure my applications right to route via it.

        This is a notes because I had forgetten I had done a thing!

        • Remember that in Home Assistant, there will need to be an entry under “http” in “trusted proxies” section for the server doing the work.
          • This was mainly caused by the fact that I was changing from a “co-locating” the docker containers that I use for HA and NPM to ones that had to route between servers.
            • My original values listed 172.20.x.x and I now needed to list the server IP address.
      • Transfer Portainer to a different host

        Transfer Portainer to a different host

        I use the product Portainer to manage the various docker containers I have at home. Periodically, I change my infrastructure set up, which results in my having to transfer the Portainer containers to a different server.

        This time, I have decided to document what I did, in an attempt to not have to recreate the wheel next time I need to perform this activity.

        1. Check you have the command line for starting Portainer.
          • Obviously, you will need this to start up portainer when it gets where it is going.
        2. Make a volume on the new host.
          • This will hold a copy of the persisted Portainer data.
        3. Stop portainer on the old host
        4. Backup the old volume on the old host.
          • You’ll likely need to be root to view the folder correctly.
        5. Transfer the backed up file to the new host using scp.
        6. Restore the backup file into the volume on the new host.
          • You’ll likely need to be root to get the permissions correct.
        7. Startup portainer using the volume
          • At this point the transfer of Portainer is technically complete.
        8. Test you can connect to portainer.
        9. Startup portainer agent on the old host.
          • This is so that I have access to the old host again.
            I’m going to need this to clean up the old host.
        10. Redirect the proxy.
          • I use NPM and I needed to fix the proxy to fetch portainer from the new host.
        11. Clean up stacks
          • In this situation i am moving to a new Lab server, so I have copied stacks from the old host to the new host, manually backing up and transferring volumes as required.
      • Install System Shock 2 on Batocera

        Install System Shock 2 on Batocera

        Installing System Shock 2 onto Batocera has proved to be tricky. The eventual solution I found these posts here:

        https://www.systemshock.org/index.php?topic=106.0

        https://www.systemshock.org/index.php?topic=4141.0

        It turns out that all that is needed is the content of the Sshock2 directory. Put that on a standard Windows PC – not a WINE instance at this stage.

        The get and run ss2tool on this directory – I tried in WINE, but the RSYNC that it needs to run would not work for some reason.

        Finally, copy the Sshock2 directory into a WINE location. This should be made using the command line as shown in WINE in Batocera.

        Everything should now work.

      • WINE in Batocera

        WINE in Batocera

        These are my notes from attempting to get some older versions of games working under WINE in Batocera.

        This makes a win32 instance:

        WINEARCH=win32 WINEPREFIX=/userdata/roms/windows/SystemShock2.wine /usr/wine/wine-proton/bin/wine wineboot

        Enable d3dx9:

        batocera-wine windows tricks /userdata/roms/windows/CIV3.wine d3dx9

        List all tricks:

        batocera-wine windows tricks /userdata/roms/windows/CIV3.wine list-all

      • Renew LetsEncrypt in Traefik

        I’d setup Traefik to use LetsEncrypt, but due to the scarey words around rate limits etc, I felt it sensible to use the staging LetsEncrypt servers, rather than the production ones – basically I wasn’t sure how many changes I’d have to make as it has been a while since I played with any of this in anger. I assumed that Traefik would renew the certificates with LetsEncrypt when I needed production ones.

        I surprisingly got this working quite straightforwardly – I had more issues with getting Apache and WordPress (mainly Apache) playing nicely with everything.

        However, the staging certificates result in a warning which I didn’t want any longer than necessary. Since it now was working, I altered my certificate resolver in Traefik to point to the production LetsEncrypt server. I then performed a bounce to pick up the changes, expecting to see a new certificate and no more errors.

        Anxious pause…

        I waited a bit (pressing F5) and was disappointed to see that it hadn’t changed. Same certificate was in use, and I could see in the log that no attempt had been made to fetch a new certificate.

        Frantic prodding ensued as I attempted to work out what I had done wrong. Nothing was the answer. The problem, such as it is, is that Traefik already has a certificate that it can use. Traefik doesn’t feel it needs to change it the certificate.

        Solution?

        A quick google later found me a couple of links:

        Whilst the last link on the face of it initially seemed less relevant (it related to fixing a security flaw), on reading it gave the simplest answer for my situation.

        In my situation, it looked like I could simply delete the storage acme.json file. No certificates needed to be kept – I could just start again from scratch.

        I stopped Traefik, moved acme.json out of the way (belts and braces right), and then restarted it.

        Traefik Renew from LetsEncypt!

        Hey, Presto! I could see in the log file the lack of certificate being identified and Traefik calls to renew certificates from the production LetsEncrypt server.

        Padlock look right, everything is gravy! Let’s move on to the next thing.