Blog

  • Moving Nftable to Seperate File for better syntax highlighting

    Moving Nftable to Seperate File for better syntax highlighting

    Reading code with no syntax highlighting is a PAIN

    I have been trying to use nftable instead of iptable for my firewall on my homelab machine. The difficulty of writing nftable rules with syntax highlighting is gnarly. Especially with security, being able to parse thru the code syntax highlighting is a must.

    The Plan

    1. Move the long string into a separate file.
    2. Add some LSP or parser for nftable.
    3. Read file as string in nix conf.

    Execution

    Turns out nftable parsing is quite hard. There are only two vim plugins that support nftable parsing and they are only syntax highlighting. I am currently using NVF to manage my nvim conf. “vim-syntax-nftables” looks very new and got some AI coding in it. “vim-nftables” hasn’t been updated in 5 years but it is available in nix packages. I will be using “vim-nftables”. This could be a great option to add some maintainer for “vim-nftable”.

    Adding vim-nftables to nvf:

      programs.nvf = {
        enable = true;
        settings = {
          vim.extraPlugins = with pkgs.vimPlugins; {
            vim-nftables = {
              package = vim-nftables;
            };
          };
      };

    We get our syntax highlighting!!

    consistent formatting is still an issues. Will find some formatters for nftables.

    And finally we load the file as a string and we are gucci πŸ˜‰

      networking.nftables = {
        enable = true;
        ruleset = builtins.readFile ./firewall.nft;
      };

    References

    https://github.com/egberts/vim-syntax-nftables

    https://github.com/nfnty/vim-nftables

  • Copying Text from Terminal in a SSH Session

    Copying Text from Terminal in a SSH Session

    Why is it even a problem?

    I have recently switch my set up from vscode to nvim and do coding completely from a terminal. All is great! Nixos makes my life pretty easy with the declarative config files. As i was copying my Nix from my remote server via my terminal it was telling me “clipboard: No provider”.

    I am surprised this is an issue! This is such a common operation to do as a system admin, how is this not set up by default?

    Turns out the issue was from Alacritty. Although Alacritty’s focus as a terminal emulator is performance, the draw back is that some features will not come out of the box. Nvim can do copying across the network via clipboard with OSC52 but it needs a terminal emulator that supports XTGETTCAP to tell Nvim to use OSC52 as the clipboard provider. Alacritty has no such support. This sent me into a rabbit hole. Should I switch terminal emulator? if so which one? if not invest more time configuring Alacritty?

    Decisions, Rabbit Holes, Productivity

    I tend to get into rabbit hole trying to find the balance of convenience, support, performance for doing anything. Analysis Paralysis. Here are the contestants from my research: Alacritty, Kitty, Wezterm, Ghostty. I want something that works and not have to tinker so much, so Alacritty is out. Ghostty is still a little new, came out of beta for just about a year. So still kinda iffy on it. I’ve heard great things about it tho. So it is down to Wezterm and Kitty. I am picked Wezterm for configuration via Lua script.

    First Hick up as with all things

    Things never go smooth… When I installed Wezterm via Nix, the window decoration was missing! I can’t window or resize it!

    Turns out Wezterm is kinda broken in wayland πŸ™

    Deeper research and I find that we need to turn off wayland for it to behave normally. I tried many things like changing the window decoration to “INTEGRATED_BUTTONS | RESIZE” and the behavior was still wonky (can’t move window or resize it). Only thing that helped was changing the wayland support. Here is my nix config for Wezterm:

      programs.wezterm = {
        enable = true;
        enableZshIntegration = true;
        extraConfig = ''
          local wezterm = require 'wezterm'
          local config = wezterm.config_builder()
          config.window_decorations = "TITLE | RESIZE"
          -- https://github.com/wezterm/wezterm/issues/4962
          config.enable_wayland = false
          return config
    
        '';
      };
    

    Now I can move the Wezterm around! And copy code from my remote server for writing this post!

    References

    https://github.com/alacritty/alacritty/issues/8376

    https://github.com/wezterm/wezterm/issues/4962

  • Migrating Nextcloud in Nixos to a Systemd container

    Migrating Nextcloud in Nixos to a Systemd container

    Why?

    I currently have a Nextcloud service running on the host Nixos system with default settings. The problems come when Nextcloud has to manage it’s own database and that would interfere with other services. For example, installing WordPress and Nextcloud would throw and error in Nixos (using the default settings) because they both want to manage the same Mysql instance. So the best approach here would be to isolate the system with Systemd containers.

    Somethings to look out for

    1. We need to create a new instance of Nextcloud in the container. (check out my previous post of creating a container isolated from home network).
    2. Back up and restore the Mysql from host instance to container instance.
    3. Bind mount the secrets (admin password) to the container with readonly.
    4. Bind mount the data directory to the Nextcloud instance with the correct permissions from user in container. This will probably be the least trivial.

    Backup process

    Put the Nextcloud instance to maintenance mode.

    nextcloud-occ maintenance:mode --on

    Backup mysql database.

    mysqldump --single-transaction -u root nextcloud > nextcloud-sqlbkp_date +"%Y%m%d".bak

    Create a container for Nextcloud. Create a temporary domain name

      containers.nextcloud = {
        autoStart = true;
        privateNetwork = true;
        hostAddress = "10.0.0.5";
        localAddress = "10.0.0.6";
        # pass decrypted secret into container
        bindMounts."/run/secrets/nextcloud/adminpass" = {
          hostPath = config.sops.secrets."nextcloud/adminpass".path;
          isReadOnly = true;
        };
        config = {
          config,
          pkgs,
          lib,
          ...
        }: {
          services.nextcloud = {
            enable = true;
            hostName = "nextcloud2.your-local-domain.com";
            # https = true;
            package = pkgs.nextcloud33;
            # [...]
            # Instead of using pkgs.nextcloud29Packages.apps or similar,
            # we'll reference the package version specified in services.nextcloud.package
            extraApps = {
              inherit
                (config.services.nextcloud.package.packages.apps)
                calendar
                contacts
                mail
                notes
                onlyoffice
                tasks
                cospend
                phonetrack
                news
                ;
            };
            extraAppsEnable = true;
            # datadir = "/mypool/nextcloud/";
            database.createLocally = true;
            configureRedis = true;
            config = {
              adminuser = "your-username";
              dbtype = "mysql";
              adminpassFile = "/run/secrets/nextcloud/adminpass";
            };
            #settings behind https nginx
            settings = {
              trusted_proxies = ["10.0.0.5"]; # The Host's container IP
              overwriteprotocol = "https";
            };
          };
          networking.firewall.allowedTCPPorts = [80];
          system.stateVersion = "26.05"; # Required for running NixOS containers
        };
      };

    Put the Nextcloud instance in the container in maintenance mode.
    Transfer the database backup file into the container and rewrite the database using the Nextcloud “Backup and Restore” below:
    https://docs.nextcloud.com/server/stable/admin_manual/maintenance/restore.html

    Things getting Tricky

    After the database restoration in the container instance, Nextcloud still needs access to data directory. We will then disable the Nextcloud instance running on the host operating system by commenting out the instance and run the rebuild. (This is where Nixos shines. No need to execute commands in the terminal. The config file will do everything for you).

    # nixos-rebuild switch --flake ~/nixos-config#machine-name

    After which we can mount the directory into the container directory and rewrite the folder’s permission to the Nextcloud user in the container.

      containers.nextcloud = {
        ...
        bindMounts."/mypool/nextcloud/" = {
          hostPath = "/mypool/nextcloud/";
          isReadOnly = false;
        };
        ...
        services.nextcloud = {
          datadir = "/mypool/nextcloud/";
        };
      };

    After you have checked everything is working, we can switch to our desired domain and have our reverse proxy Nginx point to the container instance. One the thing to note is that our Nginx is responsible for the HTTPS request and only communicate in HTTP with the container.

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Client ──── Nginx       ────│Nextcloud β”‚
    β”‚ Https  β”‚  β”‚ Https - Httpβ”‚   β”‚Container β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚Http      β”‚
                                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

    References

    https://discourse.nixos.org/t/host-permissions-for-container-bindmount/30613
    https://docs.nextcloud.com/server/stable/admin_manual/maintenance/restore.html

  • Getting WordPress Running on Nixos

    Getting WordPress Running on Nixos

    Running WordPress on Nixos has some distinct key advantage:
    1. Reproducibility: Entire system configuration down to every bit is stored in a human readable file.
    2. Easy Auditing: We can audit the entire system just by reading the file.
    3. Idempotent: System state will be same when applied multiple times.

    and many more.

    Pain points:
    1. Nix: a new domain specific language to learn
    2. Software lacking Nix support. Not all configuration are exposed via nix.
    3. The reproducibility forces you note down hash values of dependency. Sometimes make it harder to get something working.

    Running self hosted WordPress with security in mind

    We will implement the following isolation for security:
    1. System isolation: Use Systemd containers because of native support from Nixos and lighter weight than VM.
    2. Network Isolation: Create a virtual interface with it’s own subnet to isolate the system from the home network.
    3. Implement HTTPS with Nginx as reverse proxy: With reverse proxy we can host multiple services with different domains.

    Creating a container to host WordPress

    
      containers.wordpress = {
        autoStart = true;
        privateNetwork = true;
        hostAddress = "10.0.0.1";
        localAddress = "10.0.0.3";
        config = {
          config,
          pkgs,
          lib,
          ...
        }: let
          wordpress-theme-responsive = pkgs.stdenv.mkDerivation rec {
            name = "responsive";
            version = "4.7.9";
            src = pkgs.fetchzip {
              url = "https://downloads.wordpress.org/theme/responsive.${version}.zip";
              hash = "sha256-7K/pwD1KAuipeOAOLXd2wqOUEhwk+uNGIllVWzDHzp0=";
            };
            installPhase = "mkdir -p $out; cp -R * $out/";
          };
        in {
          services.wordpress.sites."wordpress.your_domain_name.com" = {
            settings = {
              # Needed to run behind reverse proxy
              FORCE_SSL_ADMIN = true;
            };
            extraConfig = ''
              $_SERVER['HTTPS']='on';
            '';
            themes = {
              inherit (pkgs.wordpressPackages.themes) twentytwentyfive;
              inherit wordpress-theme-responsive;
            };
          };
          networking.firewall.allowedTCPPorts = [80];
          system.stateVersion = "26.05"; # Required for running NixOS containers
        };
      };

    Creating network isolation to host WordPress

    We use nftable to drop all packets unless it a connection has been established.

    ct state established,related accept
    iifname "ve-*" drop

    This will prevent our wordpress container from having access to out network if it gets hacked.

    Implement HTTPS and reverse proxy with Nginx

    this assuming you already have reverse ddns setup with your domain name host.

      services.nginx.virtualHosts."wordpress.your_domain_name.com" = {
        forceSSL = true;
        enableACME = true;
        locations."/" = {
          proxyPass = "http://10.0.0.3";
        };
      };

    Bam! your got yourself a running wordpress instance isolated from your home network. The reverse proxy will allow you add more service to your server. The systemd container will let your system share resources while being isolated.

    References

    https://nixos.wiki/wiki/Wordpress

    https://nixos.wiki/wiki/Nginx