{ flake, ... }: let inherit (flake.config.people) user0; inherit (flake.config.services.instances) forgejo smtp web ; service = forgejo; host = forgejo.domains.url0; secrets = service.secretPaths.path0; localhost = web.localhost.address1; sshPort = 22; in { microvm = { vms = { forgejo = { autostart = true; config = { config, pkgs, ... }: { system.stateVersion = "25.05"; time.timeZone = "America/Winnipeg"; users.users.root = { openssh.authorizedKeys.keys = flake.config.people.users.${user0}.sshKeys; }; services = { forgejo = { enable = true; database.type = "postgres"; lfs.enable = true; dump = { interval = "5:00"; type = "zip"; file = "forgejo-backup"; enable = true; }; settings = { server = { DOMAIN = host; ROOT_URL = "https://${host}/"; HTTP_PORT = service.ports.port0; HTTP_ADDR = localhost; }; # If you need to start from scratch, don't forget to turn this off again service.DISABLE_REGISTRATION = false; actions = { ENABLED = true; DEFAULT_ACTIONS_URL = "github"; }; mirror.ENABLED = true; mailer = { ENABLED = true; SMTP_ADDR = smtp.hostname; FROM = smtp.email.address1; USER = smtp.email.address1; PROTOCOL = "${smtp.name}+${smtp.records.record1}"; SMTP_PORT = smtp.ports.port1; SEND_AS_PLAIN_TEXT = true; USE_CLIENT_CERT = false; }; }; }; openssh = { enable = true; settings = { PasswordAuthentication = false; PermitRootLogin = "prohibit-password"; }; }; }; systemd = { tmpfiles.rules = [ "d ${secrets} 0755 ${service.name} ${service.name} -" "d /run/forgejo 0755 ${service.name} ${service.name} -" ]; services.copy-forgejo-secrets = { description = "Prepare Forgejo secrets environment file"; before = [ "forgejo.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; User = service.name; Group = service.name; }; script = '' cat > /run/forgejo/env << EOF FORGEJO__database__PASSWD=$(cat /run/secrets/${service.name}-database) FORGEJO__mailer__PASSWD=$(cat /run/secrets/${service.name}-smtp) EOF chmod 600 /run/forgejo/env ''; }; services.forgejo = { serviceConfig = { EnvironmentFile = "/run/forgejo/env"; }; }; services.forgejo-dump = { serviceConfig = { ExecStartPost = "${pkgs.nushell}/bin/nu -c 'ls ${service.varPaths.path0}/dump | where name =~ forgejo-backup and modified < ((date now) - 7day) | each { rm $in.name }'"; }; }; network = { enable = true; networks."10-enp" = { matchConfig.Name = "enp0s4"; # Option 1: Static IP (recommended if you need consistent IP for reverse proxy) addresses = [ { Address = "${service.interface.ip}/24"; } ]; routes = [ { Destination = "0.0.0.0/0"; Gateway = "192.168.50.1"; # Your LAN gateway - adjust if different } ]; dns = [ "192.168.50.1" ]; # Your LAN DNS - adjust if different # Option 2: DHCP (uncomment below and comment out above if preferred) # Note: You'll need to update the Caddy reverse_proxy IP or use hostname # networkConfig.DHCP = "yes"; }; }; }; networking.firewall.allowedTCPPorts = [ sshPort service.ports.port0 ]; microvm = { vcpu = 2; mem = 3096; hypervisor = "qemu"; interfaces = [ { type = "tap"; id = service.interface.id; mac = service.interface.mac; } { type = "user"; id = service.interface.idUser; mac = service.interface.macUser; } ]; shares = [ { mountPoint = "/nix/.ro-store"; proto = "virtiofs"; source = "/nix/store"; tag = "read_only_nix_store"; } { mountPoint = service.varPaths.path0; proto = "virtiofs"; source = service.mntPaths.path0; tag = "${service.name}_data"; } { mountPoint = service.secretPaths.path0; proto = "virtiofs"; source = service.secretPaths.path0; tag = "${service.name}_secrets"; } { mountPoint = service.ssl.path; proto = "virtiofs"; source = service.ssl.path; tag = "acme_certs"; } { mountPoint = "/run/secrets"; proto = "virtiofs"; source = "/var/lib/secrets"; tag = "run_secrets"; } ]; forwardPorts = [ { from = "host"; host.port = service.interface.ssh; guest.port = sshPort; } ]; }; }; }; }; }; systemd.tmpfiles.rules = [ "d ${service.mntPaths.path0} 0755 root root -" "d ${service.secretPaths.path0} 0755 root root -" ]; services.caddy.virtualHosts."${host}" = { extraConfig = '' reverse_proxy ${service.interface.ip}:${toString service.ports.port0} tls ${service.ssl.cert} ${service.ssl.key} ''; }; sops = let sopsPath = secret: { path = "${secrets}/${service.name}-${secret}"; owner = "root"; mode = "600"; }; in { secrets = builtins.listToAttrs ( map (secret: { name = "${service.name}/${secret}"; # it's vaultwarden/env, not vaultwarden-env value = sopsPath secret; }) [ "database" "smtp" ] ); }; }