diff --git a/secrets/mcp.yaml b/secrets/mcp.yaml index 43f4ec7..fcd8cc0 100644 --- a/secrets/mcp.yaml +++ b/secrets/mcp.yaml @@ -4,6 +4,8 @@ bookstack_db: ENC[AES256_GCM,data:m8fGgAfmJu1rEaxmTVH4FfBhyiU=,iv:OnBT/6sp9zmcJ1 mariadb_root_password: ENC[AES256_GCM,data:p965ZhFQqqX+Ub1yhgklVYlBH6A=,iv:qC5WwTvZGvlbAkYiv35xHizMYAnP0V0Vw79EkvL32wQ=,tag:gOJQvHeOC9turFKOMQ9DNg==,type:str] openproject: secret-key-base: ENC[AES256_GCM,data:luTuUtxL/SGx6O10y9cRiAzJHw==,iv:8qVJm+obsHr9eV0h+jdpsreeFGxEM+UFZHHiIUUPs6w=,tag:+zpjhKoIiNNSSYxe1QkQ7Q==,type:str] +focalboard: + database: ENC[AES256_GCM,data:GDxYdkVV+tl3qHxWMMoetmMnLnY=,iv:JujgNPyUEHCmD/yW3UKCTj9GTk9a7EkvUiyFLF4sF8A=,tag:46YZ7AthpiiaX69aN9a3Bg==,type:str] sops: kms: [] gcp_kms: [] @@ -28,8 +30,8 @@ sops: by9aNFY4dXNxaWxnTXFTQS9reHhuQWMKh5rZ93nFtBV9EpFVRp+E+GXZ6xzVy2Jw vFh4deGcAb60q4odSaeWfk1Dr7L9Ua69oK9omjbCNUt+P7Kwlfca7Q== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-04-03T19:04:17Z" - mac: ENC[AES256_GCM,data:DEUuXrCl3OXJ9NbfLoxHIND5+m7enHNDbuLE2jS8nvZCpKm83YoXwp0RhIFA725wJnBej26HLkovCi7V/4s5NrrfT9sPHGNBMSHB0AAcwu3Dmo6G2PBKvAWZTxXmiIXGx8vSvWNbLrp3vTV8jjTpfbuMvOiuxayKfn6esKI9T2o=,iv:zUfbL753Uvzg6WW4kwI8swmpWHIQ/IpCyYSsLptVDG4=,tag:XZy8jNZYYcqspd6zptH3pQ==,type:str] + lastmodified: "2025-04-21T19:34:54Z" + mac: ENC[AES256_GCM,data:D44YsnrRpYQmJxAjXdap+Ya6iqPrhdEmiaTgUOM53JYmkihIvmMxm3b09xMxucv3B7tvi5vCfcllgij+RZ2RPnQDFg8ZzYQu7AQSG8rgwoh3E9Zijx2gQm59hhvJlca2cB710hUL87Tkdbvz26LZevIf5gP83u2JCkXLzr9O/Ew=,iv:lMthECFXzbao4bVVK9eJgK5ubu1NUg97BI2T9OqlICw=,tag:8t+2kPoqKeSKF8e+x5dtmg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4 diff --git a/system/hosts/mcp/containers.nix b/system/hosts/mcp/containers.nix index 19c8655..5762a52 100644 --- a/system/hosts/mcp/containers.nix +++ b/system/hosts/mcp/containers.nix @@ -4,12 +4,12 @@ # Additional configuration imports = [ ./containers/bookstack.nix + ./containers/focalboard.nix ./containers/gitea.nix ./containers/grafana.nix ./containers/jobhunt.nix ./containers/mariadb.nix ./containers/nextcloud.nix - ./containers/openproject.nix ./containers/prometheus.nix ./containers/pocket-id.nix ./containers/public-homepage.nix diff --git a/system/hosts/mcp/containers/focalboard.nix b/system/hosts/mcp/containers/focalboard.nix new file mode 100644 index 0000000..47be53a --- /dev/null +++ b/system/hosts/mcp/containers/focalboard.nix @@ -0,0 +1,74 @@ +{ config, ... }: +let + inherit (import ./lib.nix config) mkContainer mkPostgresContainer terakoda; + userIds = import ./user-ids.nix; + +in { + imports = [ + (mkPostgresContainer { + name = "focalboard"; + directory = "/tank/focalboard/db"; + uid = userIds.focalboard.uid; + gid = userIds.focalboard.gid; + passwordSecret = "focalboard/database"; + }) + ]; + + users.groups.focalboard = { + gid = userIds.focalboard.gid; + }; + + users.users.focalboard = { + uid = userIds.focalboard.uid; + isSystemUser = true; + description = "System User for Focalboard"; + group = "focalboard"; + }; + + sops.secrets = { + "focalboard/database" = { + restartUnits = [ "podman-focalboard.service" "podman-focalboard-postgres.service" ]; + mode = "0400"; + owner = config.users.users.focalboard.name; + }; + }; + + sops.templates."focalboard-config.json" = { + restartUnits = [ "podman-focalboard.service" ]; + owner = config.users.users.focalboard.name; + content = builtins.toJSON { + # Defaults from https://github.com/mattermost-community/focalboard/blob/main/config.json + "serverRoot" = "https://focalboard.terakoda.com"; + "port" = 8000; + "dbtype" = "postgres"; + "dbconfig" = "postgres://focalboard:${config.sops.placeholder."focalboard/database"}@focalboard-postgres/focalboard?sslmode=disable&connect_timeout=10"; + "useSSL" = true; + "prometheus_address" = ":9092"; + "session_expire_time" = 2592000; + "session_refresh_time" = 18000; + "postgres_dbconfig" = "dbname=focalboard sslmode=disable"; + "webpath" = "./pack"; + "filespath" = "./data/files"; + "telemetry" = true; + "prometheusaddress" = ":9092"; + "enableLocalMode" = true; + "localModeSocketLocation" = "/var/tmp/focalboard_local.socket"; + }; + }; + + virtualisation.oci-containers.containers = { + focalboard = mkContainer { + image = "mattermost/focalboard"; + hostName = "focalboard"; + domain = terakoda; + dependsOn = [ "focalboard-postgres" ]; + port = 8000; + user = "${toString userIds.focalboard.uid}:${toString userIds.focalboard.gid}"; + volumes = [ + "/tank/focalboard/data/files:/opt/focalboard/data/files" + "${config.sops.templates."focalboard-config.json".path}:/opt/focalboard/config.json:ro" + ]; + }; + }; + +} diff --git a/system/hosts/mcp/containers/lib.nix b/system/hosts/mcp/containers/lib.nix index 1e540ad..e1ec22e 100644 --- a/system/hosts/mcp/containers/lib.nix +++ b/system/hosts/mcp/containers/lib.nix @@ -2,6 +2,8 @@ config: let havenisms = "havenisms.com"; blazestar = "blazestar.net"; + terakoda = "terakoda.com"; + terakoda_net = "terakoda.net"; hostRule = host: domain: "Host(`${host}.${domain}`)"; hostRuleHavenisms = host: hostRule host havenisms; localNet = "192.168.0.0/16"; @@ -18,46 +20,42 @@ in localHostRuleHavenisms havenisms blazestar - ; + terakoda + terakoda_net; - mkContainer = - { - image, - hostName, - port, - homepageOpts, - dependsOn ? [ ], - domain ? havenisms, - ports ? [ ], - volumes ? [ ], - environment ? { }, - environmentFiles ? [ ], - public ? false, - }: + mkContainer = { + image, + hostName, + port, + homepageOpts ? {}, + dependsOn ? [], + domain ? havenisms, + ports ? [], + volumes ? [], + environment ? {}, + environmentFiles ? [], + public ? false, + user ? null, + }: let routerRule = if public then hostRule hostName domain else localHostRule hostName domain; + homepageLabels = if homepageOpts == {} then {} else { + "homepage.group" = "${homepageOpts.group}"; + "homepage.name" = "${homepageOpts.name}"; + "homepage.icon" = "${homepageOpts.icon}"; + "homepage.href" = "https://${hostName}.${domain}"; + "homepage.description" = "${homepageOpts.description}"; + }; in { - inherit - image - dependsOn - volumes - environment - environmentFiles - ports - ; + inherit image dependsOn volumes environment environmentFiles ports user; hostname = "${hostName}.${domain}"; autoStart = true; - extraOptions = [ - "-l=traefik.enable=true" - "-l=traefik.http.routers.${hostName}.rule=${routerRule}" - "-l=traefik.http.services.${hostName}.loadbalancer.server.port=${toString port}" - "-l=homepage.group=${homepageOpts.group}" - "-l=homepage.name=${homepageOpts.name}" - "-l=homepage.icon=${homepageOpts.icon}" - "-l=homepage.href=https://${hostName}.${domain}" - "-l=homepage.description=${homepageOpts.description}" - ]; + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.${hostName}.rule" = "${routerRule}"; + "traefik.http.services.${hostName}.loadbalancer.server.port" = "${toString port}"; + } // homepageLabels; }; # Creates a MariaDB container for a specific app. It should be safe to give @@ -66,33 +64,60 @@ in # user. # # Note that this returns a _module_ so that it can be imported and provide many different config values. - mkMariaDbContainer = - { - name, - uid, - gid, - passwordSecret, - directory, - }: - { config, ... }: - { - virtualisation.oci-containers.containers."${name}-mariadb" = { - image = "lscr.io/linuxserver/mariadb:latest"; - autoStart = true; - ports = [ "3306:3306" ]; - volumes = [ - "${directory}:/config" - "${config.sops.secrets.mariadb_root_password.path}:/run/secrets/mariadb_root_password" - "${config.sops.secrets."${passwordSecret}".path}:/run/secrets/mariadb_password" - ]; - environment = { - PUID = "${toString uid}"; - PGID = "${toString gid}"; - MYSQL_USER = name; - MYSQL_DATABASE = name; - FILE__MYSQL_ROOT_PASSWORD = "/run/secrets/mariadb_root_password"; - FILE__MYSQL_PASSWORD = "/run/secrets/mariadb_password"; - }; + mkMariaDbContainer = { + name, + uid, + gid, + passwordSecret, + directory, + }: + { config, ... }: + { + virtualisation.oci-containers.containers."${name}-mariadb" = { + image = "lscr.io/linuxserver/mariadb:latest"; + autoStart = true; + ports = [ "3306:3306" ]; + volumes = [ + "${directory}:/config" + "${config.sops.secrets.mariadb_root_password.path}:/run/secrets/mariadb_root_password" + "${config.sops.secrets."${passwordSecret}".path}:/run/secrets/mariadb_password" + ]; + environment = { + PUID = "${toString uid}"; + PGID = "${toString gid}"; + MYSQL_USER = name; + MYSQL_DATABASE = name; + FILE__MYSQL_ROOT_PASSWORD = "/run/secrets/mariadb_root_password"; + FILE__MYSQL_PASSWORD = "/run/secrets/mariadb_password"; }; }; + }; + + mkPostgresContainer = { + name, + uid, + gid, + passwordSecret, + directory, + containerName ? "${name}-postgres", + databaseName ? name, + username ? name, + }: { config, ... }: { + virtualisation.oci-containers.containers."${containerName}" = { + image = "postgres"; + autoStart = true; + volumes = [ + # Note that data must be mounted at this location to persist. + # See https://github.com/docker-library/docs/blob/master/postgres/README.md#pgdata + "${directory}:/var/lib/postgresql/data" + "${config.sops.secrets."${passwordSecret}".path}:/run/secrets/postgres_password" + ]; + user = "${toString uid}:${toString gid}"; + environment = { + POSTGRES_USER = username; + POSTGRES_DB = databaseName; + POSTGRES_PASSWORD_FILE = "/run/secrets/postgres_password"; + }; + }; + }; } diff --git a/system/hosts/mcp/containers/user-ids.nix b/system/hosts/mcp/containers/user-ids.nix index 3c50f15..c3c1c7a 100644 --- a/system/hosts/mcp/containers/user-ids.nix +++ b/system/hosts/mcp/containers/user-ids.nix @@ -13,4 +13,8 @@ uid = 2005; gid = 2005; }; + focalboard = { + uid = 2006; + gid = 2006; + }; }