Useful information about NixOS

Since a few years i use NixOS as my favorite Linux distribution. NixOS is a Linux distribution based on the Nix package manager and build system. It supports reproducible and declarative system-wide configuration management as well as atomic upgrades and rollbacks, although it can additionally support imperative package and user management. See NixOS Wiki.

Upgrade to new version

  1. Review the NixOS release notes to ensure you account for any changes that need to be done manually. In particular, sometimes options change in backward-incompatible ways.

  2. sudo nix-channel --add nixos (Change version tag if necessary)

  3. sudo nix-channel --update

  4. nixos-rebuild --upgrade boot

  5. Reboot to enter your newly-built NixOS.

It‘s perfectly fine and recommended to leave system.stateVersion value in the configuration at the release version of the first install of this system. You should only bump this option, if you are sure that you can or have migrated all state on your system which is affected by this option. Before changing this value read the documentation for this option (e.g. man configuration.nix or on NixOS Options).

Clean up system

  1. sudo nix-collect-garbage --delete-older-than 30d

Upgrade Kernel to latest version

  1. Add boot.kernelPackages = pkgs.linuxPackages_latest; to your configuration.nix

Use pipewire for Audio (with Bluetooth)

sound.enable = false;
hardware.pulseaudio = {
  enable = false;
  package = pkgs.pulseaudioFull;
security.rtkit.enable = true;
services.pipewire = {
  enable = true;
  alsa.enable = true;
  alsa.support32Bit = true;
  pulse.enable = true;
  # If you want to use JACK applications, uncomment this
  #jack.enable = true;

  # use the example session manager (no others are packaged yet so this is enabled by default,
  # no need to redefine it in your config for now)
  #media-session.enable = true;
  config.pipewire = {
    "" = {
      #"link.max-buffers" = 64;
      "link.max-buffers" = 16; # version < 3 clients can't handle more than this
      "log.level" = 2; #
      #"default.clock.rate" = 48000;
      #"default.clock.quantum" = 1024;
      #"default.clock.min-quantum" = 32;
      #"default.clock.max-quantum" = 8192;
  media-session.config.bluez-monitor.rules = [
      # Matches all cards
      matches = [ { "" = "~bluez_card.*"; } ];
      actions = {
        "update-props" = {
          "bluez5.reconnect-profiles" = [ "hfp_hf" "hsp_hs" "a2dp_sink" ];
          # mSBC is not expected to work on all headset + adapter combinations.
          "bluez5.msbc-support" = true;
          # SBC-XQ is not expected to work on all headset + adapter combinations.
          "bluez5.sbc-xq-support" = true;
      matches = [
        # Matches all sources
        { "" = "~bluez_input.*"; }
        # Matches all outputs
        { "" = "~bluez_output.*"; }
      actions = {
        "node.pause-on-idle" = false;

Sporadic freezing/loss of WiFi connection on a Raspberry Pi 3B+

I have two identical Raspberry Pi 3B+ (RPi3B+) running OctoPrint to control my two 3D printers and provide a livestream of the connected webcams when needed. A few months ago I noticed that the “newer” of the two RPIs sporadically lost the WiFi connection after a few minutes or hours. To check if its a a hardware problem I swapped the SD cards between both PIs, but the problem moves with the SD Card, which means its a software problem. First attempts:

  • Update system (dist-upgrade)
  • Changes the location of the Pi to ensure that the WiFi signal is better.
  • A WiFi reconnect script i used before with a Raspberry Zero W.
  • Disabled Power Management with ´sudo iwconfig wlan0 power off´

I have connected a LAN cable, waited until the connection was interrupted and tried various commands to restore the connection. Unfortunately nothing helped. I found some errors in the syslog like mailbox indicates firmware halted and some GitHub issues from RaspberryPi, but no final solution:

wlan freezes in raspberry pi 3B+
PI 3B+ wifi crash, firmware halt and hangs in dongle
brcmfmac: brcmf_sdio_hostmail: mailbox indicates firmware halted

Then I continued to search for differences between the two PIs and found out that the “working Pi” had older drivers 7.45.154 that the “problem Pi”, who had 7.45.229. I downgraded the firmware to 7.45.154 (/lib/firmware/brcm – my older Pi had these files) and disabled power management. Now, after some weeks of 8h printing each and enabled webcam no problems. With 7.45.229 and also disabled power management it freezes. The firmware files were the only thing I changed.

Working WiFi Firmware/Driver:

dmesg | grep brcmfmac
Firmware: BCM4345/6 wl0: Feb 27 2018 03:15:32 version 7.45.154 (r684107 CY) FWID 01-4fbe0b04

Final solution (tl;dr):

  1. Disabled Power Management with ´sudo iwconfig wlan0 power off´
  2. Downgrade drivers/firmware (brcm_7.45.154.tar to /lib/firmware/brcm)

Configure local Systemd-resolved DNS Resolver for Company Domains behind VPN

To send queries for the company internal (sub)-domains to the company DNS resolvers behind the VPN, the resolver can be configured with the following commands:

# Configure internal corporate domain name resolvers:
resolvectl dns tun0

# Only use the internal corporate resolvers for domain names under these:
resolvectl domain tun0 ""

# Not super nice, but might be needed:
resolvectl dnssec tun0 off

Workaround for Raspberry Pi automatic WiFi/WLAN reconnect

My old Raspberry Pi Zero W sometimes had problems restoring the WiFi connection when the AP was rebooted or reprovisioned. I don’t know why Rasbian can’t do this, but this workaround is my solution: I created a script that continuously tests the connection to the local gateway. If the gateway cannot be reached, the WiFi interface is restarted.

  • Add the following line to /etc/crontab:
*/1    *    * * *    root    /usr/local/bin/
  • Create bash script /usr/local/bin/ with this content:

#echo "Script runned @ $(date)" >>/var/log/wifi_reconnect 

# The IP for the server you wish to ping (get default getway)
SERVER=$(/sbin/ip route | awk '/default/ { print $3 }')

#echo "> Server: ${SERVER}" >>/var/log/wifi_reconnect 

# Specify wlan interface

#echo "> WLAN Interface: ${WLANINTERFACE}" >>/var/log/wifi_reconnect

# Only send two pings, sending output to /dev/null
ping -I ${WLANINTERFACE} -c2 ${SERVER} >/dev/null 

# If the return code from ping ($?) is not 0 (meaning there was an error)
if [ $? != 0 ]
echo "> WiFi doenst work. Restart!" >>/var/log/wifi_reconnect 
# Restart the wireless interface
ip link set wlan0 down
ip link set wlan0 up
#echo "> WiFi works. No restart" >>/var/log/wifi_reconnect

I added some “echo to file” lines. Remove the # to log what the script does.

Grafana/Telegraf show 0 bytes memory usage for docker containers

Today i searched for a problem with a docker container. Since there was a problem with the memory usage of the container, I wanted to check it in my Grafana. But unfortunately, the Telegraf plugin showed 0 bytes for each container since months. I founded the solution the the Telegraf GitHub issues. You need to enable memory control groups on Raspberry Pi. To do that, add the following to your /boot/cmdline.txt to enable this metic:

cgroup_enable=memory cgroup_memory=1

And after reboot, it works:

Run iotop tcpdump etc. on Synology DiskStation or RackStation with Synogear

When you need tools like iotop or tcpdump on you Synology DiskStation or RackStation, you doens’t need to itall it via ipkg. Synology had a build in way to install the tools.

  • Connect via SSH to your NAS
  • Run sudo synogear install
  • Now you could use the tools from the list below

The package “Diagnosis Tool” are now also visible in the package center. You could also uninstall it from here, but a installation from package center is not possible.


Add languages to PHP Docker Container

Recently I have noticed that the output of the following code shows the month in the wrong language (English instead of German):

setlocale(LC_ALL, 'de_DE.utf8');
$date_now = date('Y-m-d');
echo strftime('%B %Y', strtotime($date_now));

This can be solved by installing the required language in the docker container. Unfortunately there is a bug which prevents that the languages can be easy activated by locale-gen <lang-code>. So you have to enable them in /etc/locale.gen first and then generate them with locale-gen. This code solves the problem:

FROM php:7-apache


# install localisation
RUN apt-get update && \
    # locales
    apt-get install -y locales

# enable localisation and generates localisation files
RUN sed -i -e 's/# de_DE ISO-8859-1/de_DE ISO-8859-1/' /etc/locale.gen && \ # to uncomment the lange
    sed -i -e 's/# <your lang code from locale.gen>/<your lang code from locale.gen again>/' /etc/locale.gen && \


Or you could install all available languages:

FROM php:7-apache


# install localisation
RUN apt-get update && \
    # locales
    apt-get install -y locales locales-all


If you perform a dry run in the container, you must restart Apache for see the changes.

Preparing a Root-Server and install Docker-CE

This is my personal note list for preparing a root server. The list is not complete and may contain errors.

Network setup

  • Install OS as usual or use image from Control Panel

Network setup

  • Set/check fixed ip
  • Set the “Reverse DNS” entry in Control Panel
  • Add local user
    useradd <username>
    usermod -aG sudo <username>
  • Set hostname
    sudo hostnamectl set-hostname <hostname>
  • Edit the /etc/hosts file
  • Edit the /etc/cloud/cloud.cfg file if exists (preserve_hostname: false to true)


  • Add pubkey to ~/.ssh/authorized_keys
  • Disable SSH login with password and permit root login in /etc/ssh/sshd_config file
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password
  • Restart SSH Daemon
    service sshd restart


  • VIM Color open ~/.vimrc and add
    colo desert
    syntax on


  • Install docker-ce here
  • Install docker-compose
    sudo apt-get install docker-compose-plugin
  • Install docker-compose here
  • Install docker-compose command completion here
  • add username to docker group (source)
    sudo usermod -aG docker $USER

Logrotate for Docker

  • Create Logrotate config file for Docker containers under /etc/logrotate.d/docker-container with the following content:
/var/lib/docker/containers/*/*.log {
  rotate 8
  • Test it with: logrotate -fv /etc/logrotate.d/docker-container

Docker Compose aliases

  • Create or append to ~/.bash_aliases:
alias dc='docker compose'
alias dcl='docker compose logs -f --tail=200'
alias dce='docker compose exec'
alias dcb='docker compose up --build -d'
alias dcu='docker compose up -d'
alias dcul='docker compose up -d && docker-compose logs -f --tail=50'
alias dcd='docker compose down --remove-orphans'
alias dcdu='docker compose down --remove-orphans && docker compose up -d'
alias dcdul='docker compose down --remove-orphans && docker compose up -d && docker compose logs -f --tail=50' 
alias dcdb='docker compose down --remove-orphans && docker compose up --build -d'
alias dcdbl='docker compose down --remove-orphans && docker compose up --build -d && docker compose logs -f --tail=50'

Docker after dist upgrade

  • Update key
    curl -fsSL | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  • Re-enable repo
    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • update the package database with the Docker packages from the newly added repo:
    sudo apt-get update
  • Make sure you are install from the Docker repo instead of the default Ubuntu repo:
    apt-cache policy docker-ce
  • upgrade packes
    sudo apt-get install docker-ce docker-ce-cli
  • reboot


  • Install fail2ban with sudo apt-get install fail2ban
  • Create config file /etc/fail2ban/jail.local and add a jail for the SSH Deamon
enabled = true
port = <ssh port>
filter = sshd
logpath = /var/log/auth.log
maxretry = 3

enabled = true
filter = traefik
logpath = /var/lib/docker/containers/*/*-json.log
banaction = docker-action
maxretry = 3
findtime = 900
bantime = 86400

enabled = true
filter = wplogin
logpath = /var/lib/docker/containers/*/*-json.log
banaction = docker-action
maxretry = 3
findtime = 900
bantime = 86400

enabled  = true
filter   = unifi
logpath = /var/lib/docker/containers/*/*-json.log
banaction = docker-action
maxretry = 3
bantime = 86400
findtime = 900
  • Creat filter for traefik /etc/fail2ban/filter.d/traefik.conf
failregex = ^{"log":"<HOST> - \S+ \[.*\] \\"(GET|POST|HEAD) .+\" 401 .+$
ignoreregex =
  • Create filter for wplogin /etc/fail2ban/filter.d/wplogin.conf
failregex = ^{"log":"<HOST> -.*POST.*wp-login.php.*
ignoreregex =

  • Create filter for unifi /etc/fail2ban/filter.d/unifi.conf
failregex = ^{"log":"<HOST> - \S+ \[.*\] \\"POST \/api\/login.+\\" 400 .+$
  • Create action /etc/fail2ban/action.d/docker-action.conf
    Unlike the out-of-the-box action, “actionban” and “actionunban” do not affect the INPUT chain, but the docker FORWARD chain “DOCKER”.
actionstart = iptables -N f2b-docker
              iptables -A f2b-docker -j RETURN
              iptables -I FORWARD -p tcp -j f2b-docker

actionstop = iptables -D FORWARD -p tcp -j f2b-docker
             iptables -F f2b-docker
             iptables -X f2b-docker

actioncheck = iptables -n -L FORWARD | grep -q 'f2b-docker[ \t]'

actionban = iptables -I f2b-docker -s <ip> -j DROP

actionunban = iptables -D f2b-docker -s <ip> -j DROP

How to easily clone a (encrypted hard) disk over network (with dd and netcat)

The task was simple: two computers (notebooks). One – we call it A – with a working operating system (Xubuntu) and a new one – we call it B – without operating system. This is how I proceeded:

  1. Create bootable flash drive with in my case Arch-Linux
  2. In the Arch-Linux boot loader, press [TAB] and add “copytoram” to the boot command to load the squashfs image into ram. I needed this because in this case I only had a flash drive at hand. If you have two, you don’t need this.
  3. List network devices:
    ip address
  4. Assign a IP adress to computer A with:
    ip address add <machine A ip adress> dev <ethernet device>

  5. To identify source disk, list all block devices with:

  6. Prepare the copy operation (do not execute yet!) with
    dd if=/dev/<source block device> bs=32M status=progress | nc <machine B ip adress> <random port number>

  7. Boot machine B from the same or different flash drive
  8. Assign different IP adress
  9. Identify target device
  10. Prepare the receiving copy operation with
    nc -l -p <same port number as A> | dd of=/dev/<destination block device> bs=32M status=progress

  11. Execute the command on Machine B
  12. Then execute the command on Machine A
  13. Wait until the copying process is completed.
  14. Use at least the Sync command to synchronize corresponding file data in volatile storage and permanent storage
  15. Restart the machine, you are done

How it works/remarks
dd reads the source drive bit by bit into the normal output stream. The output stream is piped to netcat, which sends it over the network to a receiving netcat process (server with -l). Therefore the server must be started first. The server receives the bits and piped them back to dd, which writes them to the target on machine B.

Maybe this is not the best and/or most efficient way, but transfer speed in my case of 75MB/s (poor performance on screenshots is from a setup with two vm’s) is in IHMO very good for this simple setup.

Thanks to pmenke for his support.

Windows 10 1903 – BSOD (WDF_VIOLATION)

After updating an iMac Late 2010 to Windows 10 1903 I got a blue screen “WDF_VIOLATION”. After checking the minidump, I could see that the MacHALDriver.sys (Macintosh Hardware Application Layer Driver) is involved. After renaming the file (c:\windows\system32\drivers\MacHALDriver.sys) over the network (works because the system crashes after user login) or in safe mode and rebooting, I was able to log back in. Since I don’t use an Apple keyboard I can do without the driver.

While researching I found out that other users also have problems with a similar keyboard driver for HP. In this case it is called HpqKbFiltr.sys. Is also responsible for the hotkeys (screen brightness and co.).