diff --git a/common/_containers/forgejo.nix b/common/_containers/forgejo.nix new file mode 100644 index 0000000..92793a9 --- /dev/null +++ b/common/_containers/forgejo.nix @@ -0,0 +1,196 @@ +{ + config, + lib, + ... +}: +let + name = "forgejo"; + + hostDataDir = "/var/lib/${name}"; + + hostAddress = "10.0.0.1"; + containerAddress = "10.0.0.2"; + hostAddress6 = "fc00::1"; + containerAddress6 = "fc00::2"; + + binds = [ + # Postgres data, must use postgres user in container and host + { + host = "${hostDataDir}/postgres"; + # Adjust based on container postgres data dir + container = "/var/lib/postgresql/17"; + user = "postgres"; + uid = config.ids.uids.postgres; + gid = config.ids.gids.postgres; + } + # Postgres backups + { + host = "${hostDataDir}/backups/postgres"; + container = "/var/backup/postgresql"; + user = "postgres"; + uid = config.ids.uids.postgres; + gid = config.ids.gids.postgres; + } + # App data, uses custom user uid + { + host = "${hostDataDir}/data"; + container = "/var/lib/forgejo"; + user = "forgejo"; + uid = 115; + gid = 115; + } + ]; + uniqueUsers = lib.foldl' ( + acc: bind: if lib.lists.any (item: item.user == bind.user) acc then acc else acc ++ [ bind ] + ) [ ] binds; + users = { + users = lib.listToAttrs ( + lib.map (u: { + name = u.user; + value = { + isSystemUser = true; + name = u.user; + uid = u.uid; + group = u.user; + }; + }) uniqueUsers + ); + + groups = lib.listToAttrs ( + lib.map (g: { + name = g.user; + value.gid = g.gid; + }) uniqueUsers + ); + }; +in +{ + # Ensure users exists on host machine with same IDs as container + inherit users; + + # Ensure directories exist on host machine + system.activationScripts.createMediaServerDirs = '' + ${lib.concatStringsSep "\n" ( + lib.map (bind: '' + mkdir -p ${bind.host} + chown -R ${toString bind.user}:${toString bind.gid} ${bind.host} + chmod -R 750 ${bind.host} + '') binds + )} + ''; + + containers.${name} = { + ephemeral = true; + autoStart = true; + privateNetwork = true; + hostAddress = hostAddress; + localAddress = containerAddress; + hostAddress6 = hostAddress6; + localAddress6 = containerAddress6; + bindMounts = lib.foldl ( + acc: bind: + { + "${bind.container}" = { + hostPath = bind.host; + isReadOnly = false; + }; + } + // acc + ) { } binds; + config = + { config, pkgs, ... }: + { + system.stateVersion = "24.11"; + + networking = { + firewall = { + enable = true; + allowedTCPPorts = [ + 3000 + 3032 + ]; + }; + # Use systemd-resolved inside the container + # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 + useHostResolvConf = lib.mkForce false; + }; + services.resolved.enable = true; + + # Ensure users exist on container + inherit users; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_17.withJIT; + enableJIT = true; + authentication = '' + local all all trust + host all all 127.0.0.1/8 trust + host all all ::1/128 trust + host all all fc00::1/128 trust + ''; + }; + + # Backup database + services.postgresqlBackup = { + enable = true; + }; + + services.forgejo = { + enable = true; + dump = { + enable = false; + type = "tar.gz"; + }; + database = { + type = "postgres"; + }; + settings = { + DEFAULT = { + APP_NAME = "Josh's Git"; + }; + server = { + PROTOCOL = "http"; + DOMAIN = "git.joshuabell.xyz"; + HTTP_ADDR = "0.0.0.0"; + HTTP_PORT = 3000; + + START_SSH_SERVER = true; + SSH_DOMAIN = "git.joshuabell.xyz"; + SSH_LISTEN_HOST = "0.0.0.0"; + SSH_LISTEN_PORT = 3032; # actual listen port + SSH_PORT = 3032; # used in UI + BUILTIN_SSH_SERVER_USER = "git"; + + LANDING_PAGE = "explore"; + }; + service = { + DISABLE_REGISTRATION = true; + ENABLE_BASIC_AUTHENTICATION = false; + DISABLE_USERS_PAGE = true; + DISABLE_ORGANIZATIONS_PAGE = true; + }; + repository = { + # ENABLE_PUSH_CREATE_USER = true; + # ENABLE_PUSH_CREATE_ORG = true; + DISABLE_STARS = true; + DEFAULT_PRIVATE = "private"; + }; + admin = { + DISABLE_REGULAR_ORG_CREATION = true; + USER_DISABLED_FEATURES = "deletion"; + }; + other = { + SHOW_FOOTER_POWERED_BY = false; + SHOW_FOOTER_VERSION = false; + SHOW_FOOTER_TEMPLATE_LOAD_TIME = false; + }; + migrations = { + ALLOWED_DOMAINS = "*.github.com,github.com"; + ALLOW_LOCALNETWORKS = true; + }; + }; + }; + }; + }; +} diff --git a/common/_containers/obsidian_sync.md b/common/_containers/obsidian_sync.md new file mode 100644 index 0000000..98f7e11 --- /dev/null +++ b/common/_containers/obsidian_sync.md @@ -0,0 +1,7 @@ +docker run \ + -e hostname=https://obsidiansync.joshuabell.xyz \ + -e database=obsidian_sync \ + -e username=obsidian_admin \ + -e password=$REPLACE \ + docker.io/oleduc/docker-obsidian-livesync-couchdb:master \ + deno -A /scripts/generate_setupuri.ts diff --git a/common/_containers/obsidian_sync.nix b/common/_containers/obsidian_sync.nix new file mode 100644 index 0000000..42f8b52 --- /dev/null +++ b/common/_containers/obsidian_sync.nix @@ -0,0 +1,61 @@ +{ + config, + pkgs, + ... +}: +let + cfg = config.services.obsidian_sync; +in +{ + options.services.obsidian_sync = + let + lib = pkgs.lib; + in + { + port = lib.mkOption { + type = lib.types.port; + default = 5984; + description = "Port number for Obsidian Sync CouchDB server"; + }; + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/obsidian_sync"; + description = "Directory to store Obsidian Sync data"; + }; + serverUrl = lib.mkOption { + type = lib.types.str; + description = "URL of the Obsidian Sync server"; + }; + dockerEnvFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + description = "List of environment files to be used by the Obsidian Sync container. When provided you must supply chouchdb user/password env files they will not be supplied by default."; + }; + }; + + config = { + virtualisation.oci-containers.containers = { + ############# + # obsidian_sync # + ############# + obsidian_sync = { + user = "root"; + image = "docker.io/oleduc/docker-obsidian-livesync-couchdb:master"; + ports = [ + "${toString cfg.port}:${toString cfg.port}" + ]; + environment = { + SERVER_URL = cfg.serverUrl; + COUCHDB_DATABASE = "obsidian_sync"; + COUCHDB_USER = pkgs.lib.mkIf (cfg.dockerEnvFiles == [ ]) "adminu"; + COUCHDB_PASSWORD = pkgs.lib.mkIf (cfg.dockerEnvFiles == [ ]) "Password123"; + }; + environmentFiles = cfg.dockerEnvFiles; + volumes = [ + "${cfg.dataDir}/data:/opt/couchdb/data" + "${cfg.dataDir}/config:/opt/couchdb/etc/local.d" + ]; + }; + }; + }; +} diff --git a/common/flake.nix b/common/flake.nix index 1b299be..9fcfe30 100644 --- a/common/flake.nix +++ b/common/flake.nix @@ -56,6 +56,9 @@ }; }; }; + containers = { + forgejo = import ./_containers/forgejo.nix; + }; }; homeManagerModules = { zsh = import ./_home_manager/mods/zsh.nix; diff --git a/hosts/h001/containers/default.nix b/hosts/h001/containers/default.nix index bf033b0..59cb9cd 100644 --- a/hosts/h001/containers/default.nix +++ b/hosts/h001/containers/default.nix @@ -1,9 +1,13 @@ +{ inputs }: +let + common = inputs.common; +in { ... }: { imports = [ - ./forgejo.nix + common.nixosModules.containers.forgejo ./opengist.nix ./homarr.nix ./zitadel.nix @@ -51,7 +55,14 @@ virtualisation.oci-containers.backend = "podman"; + security.acme.acceptTerms = true; + security.acme.defaults.email = "admin@joshuabell.xyz"; services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; virtualHosts = { "localhost" = { locations."/" = { @@ -59,6 +70,13 @@ }; }; + # forgejo http traffic + "git.joshuabell.xyz" = { + locations."/" = { + proxyPass = "http://10.0.0.2:3000"; + }; + }; + "_" = { default = true; locations."/" = { @@ -66,6 +84,16 @@ }; }; }; + + # STREAMS + # Forgejo ssh + streamConfig = '' + server { + listen 3032; + proxy_pass 10.0.0.2:3032; + } + ''; + }; networking.firewall.allowedTCPPorts = [ diff --git a/hosts/h001/containers/forgejo.nix b/hosts/h001/containers/forgejo.nix index bc14238..92793a9 100644 --- a/hosts/h001/containers/forgejo.nix +++ b/hosts/h001/containers/forgejo.nix @@ -65,25 +65,6 @@ let }; in { - services.nginx = { - virtualHosts = { - # forgejo http traffic - "git.joshuabell.xyz" = { - locations."/" = { - proxyPass = "http://10.0.0.2:3000"; - }; - }; - }; - # STREAMS - # Forgejo ssh - streamConfig = '' - server { - listen 3032; - proxy_pass 10.0.0.2:3032; - } - ''; - }; - # Ensure users exists on host machine with same IDs as container inherit users; diff --git a/hosts/h001/containers/opengist.nix b/hosts/h001/containers/opengist.nix index c7fb282..e529b94 100644 --- a/hosts/h001/containers/opengist.nix +++ b/hosts/h001/containers/opengist.nix @@ -29,8 +29,6 @@ in ''; services.nginx.virtualHosts."gist.joshuabell.xyz" = { - # enableACME = true; - # forceSSL = true; locations = { "/" = { proxyWebsockets = true; diff --git a/hosts/h001/containers/zitadel.nix b/hosts/h001/containers/zitadel.nix index 9dc0aca..5c24427 100644 --- a/hosts/h001/containers/zitadel.nix +++ b/hosts/h001/containers/zitadel.nix @@ -68,8 +68,6 @@ in options = { }; config = { services.nginx.virtualHosts."sso.joshuabell.xyz" = { - # enableACME = true; - # forceSSL = true; locations = { "/" = { proxyWebsockets = true; diff --git a/hosts/h001/flake.nix b/hosts/h001/flake.nix index e88622d..9a7b684 100644 --- a/hosts/h001/flake.nix +++ b/hosts/h001/flake.nix @@ -43,7 +43,7 @@ ./hardware-configuration.nix ./mods ./nginx.nix - ./containers + (import ./containers { inherit inputs; }) ( { config, pkgs, ... }: { diff --git a/hosts/h001/mods/n8n.nix b/hosts/h001/mods/n8n.nix index e80ed5e..463919a 100644 --- a/hosts/h001/mods/n8n.nix +++ b/hosts/h001/mods/n8n.nix @@ -6,8 +6,6 @@ config = { services.nginx.virtualHosts = { "n8n.joshuabell.xyz" = { - # enableACME = true; - # forceSSL = true; locations = { "/" = { proxyWebsockets = true; diff --git a/hosts/h001/mods/nixarr.nix b/hosts/h001/mods/nixarr.nix index 0f10ce6..e561c25 100644 --- a/hosts/h001/mods/nixarr.nix +++ b/hosts/h001/mods/nixarr.nix @@ -47,39 +47,35 @@ services.nginx = { virtualHosts = { "jellyfin.joshuabell.xyz" = { - enableACME = true; - # forceSSL = true; locations."/" = { proxyWebsockets = true; proxyPass = "http://localhost:8096"; }; }; "media.joshuabell.xyz" = { - enableACME = true; - # forceSSL = true; locations."/" = { proxyWebsockets = true; proxyPass = "http://localhost:5055"; }; }; - # "10.12.14.10" = { - # locations."/" = { - # proxyWebsockets = true; - # proxyPass = "http://localhost:8096"; - # }; - # }; - # "jellyfin.h001.local.joshuabell.xyz" = { - # locations."/" = { - # proxyWebsockets = true; - # proxyPass = "http://localhost:8096"; - # }; - # }; - # "media.h001.local.joshuabell.xyz" = { - # locations."/" = { - # proxyWebsockets = true; - # proxyPass = "http://localhost:5055"; - # }; - # }; + "10.12.14.10" = { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://localhost:8096"; + }; + }; + "jellyfin.h001.local.joshuabell.xyz" = { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://localhost:8096"; + }; + }; + "media.h001.local.joshuabell.xyz" = { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://localhost:5055"; + }; + }; }; }; }; diff --git a/hosts/h001/mods/oauth2-proxy.nix b/hosts/h001/mods/oauth2-proxy.nix index a2da192..bfb34fa 100644 --- a/hosts/h001/mods/oauth2-proxy.nix +++ b/hosts/h001/mods/oauth2-proxy.nix @@ -45,15 +45,11 @@ in }; services.nginx.virtualHosts."sso-proxy.joshuabell.xyz" = { - # enableACME = true; - # forceSSL = true; locations = { "/" = { proxyWebsockets = true; + recommendedProxySettings = true; proxyPass = "http://127.0.0.1:4180"; - extraConfig = '' - proxy_set_header X-Forwarded-Proto https; - ''; }; }; }; diff --git a/hosts/h001/mods/openwebui.nix b/hosts/h001/mods/openwebui.nix index 2df829d..6b9c994 100644 --- a/hosts/h001/mods/openwebui.nix +++ b/hosts/h001/mods/openwebui.nix @@ -17,8 +17,6 @@ in options = { }; config = { services.nginx.virtualHosts."chat.joshuabell.xyz" = { - # enableACME = true; - # forceSSL = true; locations = { "/" = { proxyWebsockets = true; diff --git a/hosts/h001/mods/trilium.nix b/hosts/h001/mods/trilium.nix index d532b6e..863246d 100644 --- a/hosts/h001/mods/trilium.nix +++ b/hosts/h001/mods/trilium.nix @@ -1,5 +1,6 @@ { inputs, + lib, ... }: let @@ -44,8 +45,6 @@ in }; services.nginx.virtualHosts = { "notes.joshuabell.xyz" = { - # enableACME = true; - # forceSSL = true; locations = { "/" = { proxyWebsockets = true; diff --git a/hosts/h001/nginx.nix b/hosts/h001/nginx.nix index 052aa94..8a52091 100644 --- a/hosts/h001/nginx.nix +++ b/hosts/h001/nginx.nix @@ -8,14 +8,7 @@ let }; in { - security.acme.acceptTerms = true; - security.acme.defaults.email = "admin@joshuabell.xyz"; services.nginx = { - enable = true; - recommendedGzipSettings = true; - recommendedOptimisation = true; - recommendedProxySettings = true; - recommendedTlsSettings = true; clientMaxBodySize = "500m"; virtualHosts = { "10.12.14.10" = {