NixOS config for docker containers using rootless podman

I’m very fresh to NixOS here and I’m looking to migrate a small home Fedora server to NixOS. It currently hosts a handful of popular docker images using rootless podman (eg. Unifi controller). They are each started with generated systemd units.

I’m looking for some guidance/best practice around maintaining config for the podman containers - how much of this should/can be done with nix config vs manually setting up the containers in user accounts? I’m a bit lost at this stage and there doesn’t appear to be a heap of documentation on using podman with NixOS yet.

3 Likes

NixOS has native support for the unifi controller (I’m using it), so in that specific case, I would absolutely use that rather than a container.

I wouldn’t run anything manually. Sure, you can run the binaries using whatever container image you want, but I that case I would still configure it via the NixOS module system.

2 Likes

I’m in exactly the same situation as you, thinking of switching my fedora server to NixOS , I run all my containers via systemd units, using podman as my user, so rootless containers. As you say there isn’t alot of documentation about this setup yet and from what I can tell rootless podman isn’t supported well at the moment in NixOS.

I was thinking the same as you probably, use the module as shown in the wiki, in my config.nix to run each container using systemd. However, have the unit files in my user home directory for each container still. I’m not sure this will work though. I will be testing this soon on a disused thinkpad to ‘trial and error’ getting this working.

I initially went down the route of manually configuring systemd unit files for the containers using systemd.user.services and trying to enable it with a user but it was getting unwieldy and I didn’t end up getting it to work properly. I figured even if I did then managing them ongoing would be a headache if there were changes in podman moving forward.

In the end, everything I needed was available in nixpkgs, so I’ve been gone that route instead on the advice of @peterhoeg. The only thing that’s frustrating is that mongodb takes forever to recompile for each new version (needed by unifi).

Yeah I did consider not using containers and using nixpkgs , unfortunately not all the containers I use are available as pkgs. So a bit of work ahead for me, getting it working.

I also struggled with this several months ago while moving to a NixOS/podman server. I ended up having to run the containers as systemd system services but used the User= directive to at least drop most permissions to user level. Not ideal, but it’s working well.

Happy to share configuration.

Yes please , I know you shared previously on another thread I’m on, but the paste bin expired.

Here is my podman configuration. (Edit: removed link and included file).

# Podman services
{pkgs, ...}: let
  podman-py = p:
    with p; [
      (
        buildPythonPackage rec {
          pname = "podman";
          version = "4.5.1";
          src = fetchPypi {
            inherit pname version;
            sha256 = "sha256-znZnjuOFIy6YiwbtVXoCFNnNdtVJldWpDUNXC13RygQ=";
          };
          doCheck = false;
          propagatedBuildInputs = [
            # Specify dependencies
            pkgs.python310Packages.pyxdg
            pkgs.python310Packages.requests
            pkgs.python310Packages.setuptools
            pkgs.python310Packages.sphinx
            pkgs.python310Packages.tomli
            pkgs.python310Packages.urllib3
            pkgs.python310Packages.wheel
          ];
        }
      )
    ];
in {
  environment.systemPackages = with pkgs; [
    (python310.withPackages podman-py)
  ];
  environment.shellAliases = {
    pps = "podman ps --format 'table {{ .Names }}\t{{ .Status }}' --sort names";
    pclean = "podman ps -a | grep -v 'CONTAINER\|_config\|_data\|_run' | cut -c-12 | xargs podman rm 2>/dev/null";
    piclean = "podman images | grep '<none>' | grep -P '[1234567890abcdef]{12}' -o | xargs -L1 podman rmi 2>/dev/null";
  };

  systemd.services.pod-cloud = {
    description = "Start podman 'nextcloud' pod";
    wants = ["network-online.target"];
    after = ["network-online.target"];
    requiredBy = ["podman-mariadb.service" "podman-nextcloud.service" "podman-redis.service"];
    unitConfig = {
      RequiresMountsFor = "/run/containers";
    };
    serviceConfig = {
      Type = "oneshot";
      ExecStart = "-${pkgs.podman}/bin/podman pod create cloud";
    };
    path = [pkgs.zfs pkgs.podman];
  };
  systemd.services.pod-download = {
    description = "Start podman 'download' pod";
    wants = ["network-online.target"];
    after = ["network-online.target"];
    requiredBy = ["podman-jackett.service" "podman-radarr.service" "podman-sabnzbd.service" "podman-sonarr.service"];
    unitConfig = {
      RequiresMountsFor = "/run/containers";
    };
    serviceConfig = {
      Type = "oneshot";
      ExecStart = "-${pkgs.podman}/bin/podman pod create download";
    };
    path = [pkgs.zfs pkgs.podman];
  };
  systemd.services.pod-flux = {
    description = "Start podman 'flux' pod";
    wants = ["network-online.target"];
    after = ["network-online.target"];
    requiredBy = ["podman-miniflux.service" "podman-postgres.service"];
    unitConfig = {
      RequiresMountsFor = "/run/containers";
    };
    serviceConfig = {
      Type = "oneshot";
      ExecStart = "-${pkgs.podman}/bin/podman pod create --dns=192.168.1.1 flux";
    };
    path = [pkgs.podman pkgs.zfs];
  };
  systemd.services.pod-wireguard = {
    description = "Start podman 'wg' pod";
    wants = ["network-online.target"];
    after = ["network-online.target"];
    requiredBy = ["podman-wireguard-client.service" "podman-qbitorrent.service" "podman-socks-proxy.service"];
    unitConfig = {
      RequiresMountsFor = "/run/containers";
    };
    serviceConfig = {
      Type = "oneshot";
      # 8081 - qbitorrent, 2222 - socks-proxy
      ExecStart = "-${pkgs.podman}/bin/podman pod create -p 8081:8081 -p 2222:22 wg";
    };
    path = [pkgs.zfs pkgs.podman];
  };
  systemd.timers."memories" = {
    wantedBy = ["timers.target"];
    timerConfig = {
      OnCalendar = "daily";
      OnBootSec = "5m";
      Unit = "memories.service";
    };
  };
  systemd.services."memories" = {
    script = ''
      ${pkgs.podman}/bin/podman run --rm \
      -v /home/firecat53/docs/family/scott/wiki/diary:/data/journal \
      -v /mnt/media/pictures/Family\ Pictures:/data/pictures \
      -v /srv/rss:/srv/rss \
      memories
    '';
    path = [pkgs.podman pkgs.zfs];
  };
  systemd.timers."nextcloud_cron" = {
    wantedBy = ["timers.target"];
    timerConfig = {
      OnBootSec = "2m";
      OnUnitActiveSec = "5m";
      Unit = "nextcloud_cron.service";
    };
  };
  systemd.services."nextcloud_cron" = {
    bindsTo = ["podman-nextcloud.service" "podman-mariadb.service" "podman-redis.service"];
    after = ["network-online.target" "podman-nextcloud.service" "podman-mariadb.service" "podman-redis.service"];
    script = "${pkgs.podman}/bin/podman exec -u www-data nextcloud php -f cron.php";
    path = [pkgs.podman pkgs.zfs];
  };
  systemd.timers."nextcloud_files_update" = {
    wantedBy = ["timers.target"];
    timerConfig = {
      OnBootSec = "2m";
      OnUnitActiveSec = "15m";
      Unit = "nextcloud_files_update.service";
    };
  };
  systemd.services."nextcloud_files_update" = {
    bindsTo = ["podman-nextcloud.service" "podman-mariadb.service" "podman-redis.service"];
    after = ["network-online.target" "podman-nextcloud.service" "podman-mariadb.service" "podman-redis.service"];
    script = ''
      ${pkgs.podman}/bin/podman exec -u www-data nextcloud ./occ files:scan -q --all
      ${pkgs.podman}/bin/podman exec -u www-data nextcloud ./occ memories:index -q
      ${pkgs.podman}/bin/podman exec -u www-data nextcloud ./occ preview:pre-generate
    '';
    path = [pkgs.podman pkgs.zfs];
  };
  systemd.timers."picture_copy" = {
    enable = true;
    wantedBy = ["timers.target"];
    timerConfig = {
      OnBootSec = "5m";
      OnCalendar = "daily";
      Unit = "picture_copy.service";
    };
  };
  systemd.services."picture_copy" = {
    script = "${pkgs.python3}/bin/python3 /home/firecat53/docs/family/scott/src/scripts.git/bin/pix.py";
    path = [pkgs.python3 pkgs.rsync pkgs.exiftool];
    serviceConfig = {
      User = "firecat53";
    };
  };
  systemd.timers."podman_db_backup" = {
    wantedBy = ["timers.target"];
    timerConfig = {
      OnBootSec = "5m";
      OnCalendar = "daily";
      RandomizedDelaySec = "15m";
      FixedRandomDelay = true;
      Unit = "podman_db_backup.service";
    };
  };
  systemd.services."podman_db_backup" = {
    script = let
      python3 = pkgs.python3.withPackages podman-py;
    in "${python3.interpreter} /home/firecat53/docs/family/scott/src/scripts.git/bin/podman_db_backup_homeserver.py";
    path = [pkgs.python3];
  };

  ## Podman containers

  virtualisation.podman = {
    enable = true;
    extraPackages = [pkgs.zfs];
  };
  virtualisation.containers.storage.settings = {
    storage = {
      driver = "zfs";
      graphroot = "/var/lib/containers/storage";
      runroot = "/run/containers/storage";
    };
  };
  virtualisation.oci-containers.containers = {
    gollum = {
      image = "gollum";
      autoStart = true;
      cmd = ["--allow-uploads" "page" "--ref" "main"];
      volumes = [
        "/home/firecat53/docs/family/scott/wiki:/home/gollum/wiki"
        "/home/firecat53/.gitconfig:/home/gollum/.gitconfig:ro"
      ];
      user = "1000:100";
      extraOptions = [
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.gollum.rule=Host(`gollum.domain.com`)"
        "--label=traefik.http.routers.gollum.entrypoints=websecure"
        "--label=traefik.http.routers.gollum.tls.certResolver=le"
        "--label=traefik.http.routers.gollum.middlewares=auth-gollum"
        "--label=traefik.http.middlewares.auth-gollum.basicauth.users=firecat53:$apr1$xxxxxx"
        "--label=traefik.http.services.gollum.loadbalancer.server.port=4567"
      ];
    };
    jackett = {
      image = "jackett";
      autoStart = true;
      user = "1000:100";
      extraOptions = [
        "--init=true"
        "--pod=download"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.jackett.rule=Host(`jackett.domain.com`)"
        "--label=traefik.http.routers.jackett.entrypoints=websecure"
        "--label=traefik.http.routers.jackett.tls.certResolver=le"
        "--label=traefik.http.routers.jackett.middlewares=headers"
        "--label=traefik.http.services.jackett.loadbalancer.server.port=9117"
      ];
      volumes = ["jackett_config:/config" "/mnt/downloads:/data"];
    };
    # Note: jellyfin server discovery doesn't work without host networking (ports 7359 and 1900 udp)
    jellyfin = {
      image = "jellyfin";
      autoStart = true;
      user = "1000:100";
      ports = ["1900:1900/udp" "7359:7359/udp"];
      extraOptions = [
        "--device=/dev/dri"
        "--init=true"
        "--tz=local"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.jellyfin.rule=Host(`jellyfin.domain.com`)"
        "--label=traefik.http.routers.jellyfin.entrypoints=websecure"
        "--label=traefik.http.routers.jellyfin.tls.certResolver=le"
        "--label=traefik.http.routers.jellyfin.middlewares=headers"
        "--label=traefik.http.services.jellyfin.loadbalancer.server.port=8096"
      ];
      volumes = [
        "jellyfin_config:/config"
        "jellyfin_cache:/cache"
        "/mnt/media:/media"
        "/mnt/downloads:/downloads"
      ];
    };
    mariadb = {
      image = "docker.io/library/mariadb:latest";
      autoStart = true;
      user = "mysql:mysql";
      cmd = ["--transaction-isolation=READ-COMMITTED" "--log-bin=msqyld-bin" "--binlog-format=ROW"];
      extraOptions = ["--pod=cloud"];
      volumes = ["mariadb_data:/var/lib/mysql"];
      environment = {
        MYSQL_DATABASE = "nextcloud";
        MYSQL_USER = "nextcloud";
        MYSQL_PASSWORD = "xxxxx";
        MYSQL_ROOT_PASSWORD = "yyyyyy";
      };
      dependsOn = ["redis"];
    };
    miniflux = {
      image = "miniflux";
      autoStart = true;
      user = "1000:100";
      environment = {
        DATABASE_URL = "user=miniflux password=miniflux dbname=miniflux sslmode=disable host=postgres";
        POLLING_FREQUENCY = "15";
        RUN_MIGRATIONS = "1";
      };
      dependsOn = ["postgres"];
      extraOptions = [
        "--dns=192.168.1.1"
        "--pod=flux"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.miniflux.rule=Host(`rss.domain.com`)"
        "--label=traefik.http.routers.miniflux.entrypoints=websecure"
        "--label=traefik.http.routers.miniflux.tls.certResolver=le"
        "--label=traefik.http.routers.miniflux.middlewares=headers"
        "--label=traefik.http.services.miniflux.loadbalancer.server.port=8080"
      ];
    };
    nextcloud = {
      image = "nextcloud:local";
      autoStart = true;
      user = "1000:100";
      dependsOn = ["mariadb" "redis"];
      environment = {
        MYSQL_HOST = "127.0.0.1";
        REDIS_HOST = "127.0.0.1";
        TRUSTED_PROXIES = "10.88.0.1/24";
        NEXTCLOUD_TRUSTED_DOMAINS = "nc.domain.com";
        MAIL_DOMAIN = "firecat53.net";
        OVERWRITEHOST = "nc.domain.com";
        OVERWRITEPROTOCOL = "https";
        OVERWRITECLIURL = "https://nc.domain.com";
        PHP_MEMORY_LIMIT = "2G";
        PHP_UPLOAD_LIMIT = "2G";
      };
      extraOptions = [
        "--device=/dev/dri"
        "--init=true"
        "--pod=cloud"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.nextcloud.rule=Host(`nc.domain.com`)"
        "--label=traefik.http.routers.nextcloud.entrypoints=websecure"
        "--label=traefik.http.routers.nextcloud.tls.certResolver=le"
        "--label=traefik.http.routers.nextcloud.middlewares=headers,nextcloud-redirectregex@file"
        "--label=traefik.http.services.nextcloud.loadbalancer.server.port=80"
        "--sysctl=net.ipv4.ip_unprivileged_port_start=80"
      ];
      volumes = ["nextcloud_config:/var/www/html" "/mnt/media:/data"];
    };
    nginx = {
      image = "nginx";
      autoStart = true;
      volumes = ["/srv/http:/var/www/misc:ro" "/srv/rss:/var/www/rss:ro"];
      extraOptions = [
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.nginx.rule=Host(`domain.com`) && ((PathPrefix(`/misc`) || PathPrefix(`/rss`)))"
        "--label=traefik.http.routers.nginx.entrypoints=websecure"
        "--label=traefik.http.routers.nginx.tls.certResolver=le"
        "--label=traefik.http.routers.nginx.middlewares=headers"
        "--label=traefik.http.services.nginx.loadbalancer.server.port=8080"
      ];
    };
    podman-exporter = {
      image = "podman-exporter";
      autoStart = true;
      ports = ["9882:9882"];
      volumes = ["/run/podman/podman.sock:/run/podman/podman.sock"];
      environment = {
        CONTAINER_HOST = "unix:///run/podman/podman.sock";
      };
    };
    postgres = {
      image = "docker.io/library/postgres:15-alpine";
      autoStart = true;
      user = "70:70";
      extraOptions = ["--pod=flux"];
      volumes = ["miniflux_data:/var/lib/postgresql/data"];
    };
    qbittorrent = {
      image = "qbittorrent";
      autoStart = true;
      user = "1000:100";
      dependsOn = ["wireguard-client"];
      environment = {
        QBT_WEBUI_PORT = "8081";
      };
      extraOptions = [
        "--init=true"
        "--network=container:wireguard-client"
        "--pod=wg"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.qbittorrent.rule=Host(`qbt.domain.com`)"
        "--label=traefik.http.routers.qbittorrent.entrypoints=websecure"
        "--label=traefik.http.routers.qbittorrent.tls.certResolver=le"
        "--label=traefik.http.routers.qbittorrent.middlewares=headers"
        "--label=traefik.http.services.qbittorrent.loadbalancer.server.port=8081"
      ];
      volumes = ["qbittorrent_config:/config" "/mnt/downloads:/data"];
    };
    redis = {
      image = "docker.io/library/redis:latest";
      autoStart = true;
      user = "1000:100";
      cmd = ["redis-server" "--save" "59" "1" "--loglevel" "warning"];
      extraOptions = ["--pod=cloud"];
      volumes = ["redis_data:/data"];
    };
    samba = {
      image = "samba";
      autoStart = true;
      ports = ["137:137/udp" "138:138/udp" "139:139" "445:445"];
      volumes = [
        "samba_config:/config"
        "/mnt/downloads:/mnt/downloads"
        "/mnt/media:/mnt/media"
        "/home:/home"
      ];
    };
    plex = {
      image = "docker.io/plexinc/pms-docker:latest";
      autoStart = true;
      ports = ["32400:32400" "32410:32410" "32412:32412" "32413:32413" "32414:32414"];
      volumes = ["plex_config:/config" "/mnt/downloads:/data" "/mnt/media:/mnt/media"];
      environment = {
        TZ = "America/Los_Angeles";
        PLEX_CLAIM = "claim-sg6qnQnT5p7fB8hnFmp2";
        PLEX_UID = "1000";
        PLEX_GID = "100";
        ADVERTISE_IP = "http://192.168.1.2:32400/";
        ALLOWED_NETWORKS = "192.168.1.0/24";
      };
      extraOptions = ["--device=/dev/dri" "--init=true" "--no-healthcheck"];
    };
    radarr = {
      image = "radarr";
      autoStart = true;
      user = "1000:100";
      extraOptions = [
        "--init=true"
        "--pod=download"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.radarr.rule=Host(`radarr.domain.com`)"
        "--label=traefik.http.routers.radarr.entrypoints=websecure"
        "--label=traefik.http.routers.radarr.tls.certResolver=le"
        "--label=traefik.http.routers.radarr.middlewares=headers"
        "--label=traefik.http.services.radarr.loadbalancer.server.port=7878"
      ];
      volumes = ["radarr_config:/config" "/mnt/downloads:/data"];
    };
    sabnzbd = {
      image = "sabnzbd";
      autoStart = true;
      user = "1000:100";
      extraOptions = [
        "--init=true"
        "--pod=download"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.sabnzbd.rule=Host(`sabnzbd.domain.com`)"
        "--label=traefik.http.routers.sabnzbd.entrypoints=websecure"
        "--label=traefik.http.routers.sabnzbd.tls.certResolver=le"
        "--label=traefik.http.routers.sabnzbd.middlewares=headers"
        "--label=traefik.http.services.sabnzbd.loadbalancer.server.port=8080"
      ];
      volumes = ["sabnzbd_config:/config" "/mnt/downloads:/data"];
    };
    socks-proxy = {
      image = "socks-proxy";
      autoStart = true;
      dependsOn = ["wireguard-client"];
      extraOptions = [
        "--pod=wg"
        "--network=container:wireguard-client"
      ];
    };
    sonarr = {
      image = "sonarr";
      autoStart = true;
      user = "1000:100";
      extraOptions = [
        "--init=true"
        "--pod=download"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.sonarr.rule=Host(`sonarr.domain.com`)"
        "--label=traefik.http.routers.sonarr.entrypoints=websecure"
        "--label=traefik.http.routers.sonarr.tls.certResolver=le"
        "--label=traefik.http.routers.sonarr.middlewares=headers"
        "--label=traefik.http.services.sonarr.loadbalancer.server.port=8989"
      ];
      volumes = ["sonarr_config:/config" "/mnt/downloads:/data"];
    };
    syncthing = {
      image = "syncthing";
      autoStart = true;
      ports = ["22000:22000" "22000:22000/udp" "21027:21027/udp"];
      volumes = [
        "syncthing_config:/config"
        "/mnt/media:/mnt/media"
        "/srv:/srv"
        "/var/backups:/var/backups"
      ];
      extraOptions = [
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.syncthing.rule=Host(`syncthing.domain.com`)"
        "--label=traefik.http.routers.syncthing.entrypoints=websecure"
        "--label=traefik.http.routers.syncthing.tls.certResolver=le"
        "--label=traefik.http.routers.syncthing.middlewares=headers"
        "--label=traefik.http.services.syncthing.loadbalancer.server.port=8384"
      ];
    };
    traefik = {
      image = "docker.io/library/traefik:latest";
      autoStart = true;
      ports = ["80:80" "443:443"];
      volumes = ["traefik_config:/etc/traefik" "/run/podman/podman.sock:/var/run/docker.sock"];
      extraOptions = [
        "--add-host=host.docker.internal:10.88.0.1"
        "--env-file=/root/.cloudflare"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.traefik-http.rule=Host(`monitor.domain.com`)"
        "--label=traefik.http.routers.traefik-http.entrypoints=web"
        "--label=traefik.http.routers.traefik-https.rule=Host(`monitor.domain.com`)"
        "--label=traefik.http.routers.traefik-https.entrypoints=websecure"
        "--label=traefik.http.routers.traefik-https.service=api@internal"
        "--label=traefik.http.routers.traefik-https.tls.certResolver=le"
        "--label=traefik.http.routers.traefik-https.middlewares=auth,headers"
        "--label=traefik.http.middlewares.auth.basicauth.users=firecat53:$apr1$xxxxxx"
        "--label=traefik.http.middlewares.headers.headers.browserxssfilter=true"
        "--label=traefik.http.middlewares.headers.headers.contenttypenosniff=true"
        "--label=traefik.http.middlewares.headers.headers.forcestsheader=true"
        "--label=traefik.http.middlewares.headers.headers.framedeny=true"
        "--label=traefik.http.middlewares.headers.headers.customframeoptionsvalue=SAMEORIGIN"
        "--label=traefik.http.middlewares.headers.headers.sslhost=domain.com"
        "--label=traefik.http.middlewares.headers.headers.sslredirect=true"
        "--label=traefik.http.middlewares.headers.headers.stsincludesubdomains=true"
        "--label=traefik.http.middlewares.headers.headers.stspreload=true"
        "--label=traefik.http.middlewares.headers.headers.stsseconds=315360000"
      ];
    };
    transmission = {
      image = "transmission";
      autoStart = true;
      ports = ["9091:9091" "30020:30020" "30020:30020/udp"];
      volumes = ["transmission_config:/config" "/mnt/downloads:/data"];
      user = "1000:100";
      extraOptions = [
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.transmission.rule=Host(`transmission.domain.com`)"
        "--label=traefik.http.routers.transmission.entrypoints=websecure"
        "--label=traefik.http.routers.transmission.tls.certResolver=le"
        "--label=traefik.http.routers.transmission.middlewares=auth-transmission"
        "--label=traefik.http.middlewares.auth-transmission.basicauth.users=firecat53:$apr1$xxxxxx"
        "--label=traefik.http.services.transmission.loadbalancer.server.port=9091"
      ];
    };
    unifi = {
      image = "unifi";
      autoStart = true;
      volumes = ["unifi_config:/config"];
      ports = ["3478:3478/udp" "6789:6789" "8080:8080" "8843:8843" "8880:8880" "10001:10001/udp"];
      extraOptions = [
        "--init=true"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.unifi.rule=Host(`unifi.domain.com`)"
        "--label=traefik.http.routers.unifi.entrypoints=websecure"
        "--label=traefik.http.routers.unifi.tls.certResolver=le"
        "--label=traefik.http.routers.unifi.middlewares=headers"
        "--label=traefik.http.services.unifi.loadbalancer.server.port=8443"
        "--label=traefik.http.services.unifi.loadbalancer.server.scheme=https"
        "--label=traefik.http.services.unifi.loadbalancer.passhostheader=true"
      ];
    };
    vaultwarden = {
      image = "vaultwarden";
      autoStart = true;
      user = "1000:100";
      volumes = ["vaultwarden_data:/data"];
      environment = {
        DOMAIN = "https://bw.domain.com";
        SMTP_HOST = "smtp.domain.com";
        SMTP_FROM = "from@domain.com";
        SMTP_PORT = "587";
        SMTP_SECURITY = "starttls";
        SMTP_USERNAME = "me@domain.com";
        SMTP_PASSWORD = "xxxxxx";
        ROCKET_PORT = "8080";
      };
      extraOptions = [
        "--init=true"
        "--label=traefik.enable=true"
        "--label=traefik.http.routers.vaultwarden.rule=Host(`bw.domain.com`)"
        "--label=traefik.http.routers.vaultwarden.entrypoints=websecure"
        "--label=traefik.http.routers.vaultwarden.tls.certResolver=le"
        "--label=traefik.http.routers.vaultwarden.middlewares=headers"
        "--label=traefik.http.services.vaultwarden.loadbalancer.server.port=8080"
      ];
    };
    wireguard-client = {
      image = "wireguard-client";
      autoStart = true;
      volumes = ["wireguard_config:/etc/wireguard"];
      environment = {
        LOCAL_NETWORKS = "10.1.1.0/24,192.168.1.0/24";
      };
      extraOptions = [
        "--cap-add=NET_ADMIN"
        "--cap-add=NET_RAW"
        "--dns=172.16.0.1"
        "--pod=wg"
      ];
    };
  };
  # For wireguard-client
  boot.kernel.sysctl."net.ipv4.conf.all.src_valid_mark" = 1;
}
2 Likes

Sorry to revive this thread, but the link doesn’t seem to work anymore. Do you have a link to your config? I can’t seem to get podman to work

Updated the above link, sorry! Switched my self-hosted paste provider :slight_smile:

Awesome, thank you! :slight_smile:

Hey @firecat53 any chance you could update that link again? Getting a 404.

Done, sorry! The joys of self-hosting at times :stuck_out_tongue:

2 Likes