{ config, lib, pkgs, ... }: let forgejoServer = config.services.forgejo.settings.server; in { environment.systemPackages = [ (pkgs.writeShellScriptBin "panelctl" (builtins.readFile ./panel/panelctl.sh)) ]; users.groups.panelroutes = { }; users.users.reudy.extraGroups = [ "panelroutes" ]; users.users.caddy.extraGroups = [ "panelroutes" ]; systemd.tmpfiles.rules = [ "d /var/lib/containers 0750 reudy panelroutes -" "d /var/lib/containers/stacks 0750 reudy panelroutes -" "d /var/lib/containers/volumes 0750 reudy panelroutes -" "d /var/lib/containers/routes 0750 reudy panelroutes -" "d /var/lib/containers/state 0750 reudy panelroutes -" "d /var/lib/containers/state/apps 0750 reudy panelroutes -" "d /var/lib/containers/backups 0750 reudy panelroutes -" "f /var/lib/containers/routes/routes.caddy 0640 reudy panelroutes -" ]; systemd.services.panel-api = { description = "Minimal panel API service"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; path = [ pkgs.podman pkgs.podman-compose pkgs.curl pkgs.coreutils pkgs.zip pkgs.unzip pkgs.git pkgs.util-linux # flock, used by panelctl to serialise routes file writes pkgs.openssh # cloning repositories over ssh with the panel's deploy key ]; serviceConfig = { Type = "simple"; User = "reudy"; Group = "panelroutes"; Restart = "always"; RestartSec = 3; WorkingDirectory = "/var/lib/containers"; ExecStart = "${pkgs.python3}/bin/python3 ${./panel/panel-api.py}"; }; environment = { PANEL_API_BIND = "127.0.0.1"; PANEL_API_PORT = "9911"; PANEL_BASE_DIR = "/var/lib/containers"; PANELCTL_PATH = "/run/current-system/sw/bin/panelctl"; PANEL_FRONTEND_DIR = "${./panel/frontend}"; # Forgejo integration (repo picker, private clones, commit links). # The API is reached on localhost; clones use the public URLs. PANEL_FORGEJO_URL = lib.removeSuffix "/" forgejoServer.ROOT_URL; PANEL_FORGEJO_API_URL = "http://${forgejoServer.HTTP_ADDR}:${toString forgejoServer.HTTP_PORT}"; PANEL_FORGEJO_SSH_URL = "ssh://${forgejoServer.BUILTIN_SSH_SERVER_USER}@${forgejoServer.DOMAIN}:${toString forgejoServer.SSH_PORT}"; }; }; services.caddy.virtualHosts."panel.reudy.net".extraConfig = '' forward_auth 127.0.0.1:9091 { uri /api/authz/forward-auth copy_headers Remote-User Remote-Groups Remote-Email Remote-Name } reverse_proxy 127.0.0.1:9911 ''; systemd.paths."caddy-routes-reload" = { wantedBy = [ "multi-user.target" ]; pathConfig = { PathChanged = "/var/lib/containers/routes/routes.caddy"; }; }; systemd.services."caddy-routes-reload" = { serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.systemd}/bin/systemctl reload caddy.service"; }; }; }