diff --git a/hosts/common/optional/services/glances.nix b/hosts/common/optional/services/glances.nix new file mode 100644 index 0000000..b289387 --- /dev/null +++ b/hosts/common/optional/services/glances.nix @@ -0,0 +1,10 @@ +{ + config, + lib, + ... +}: { + services.glances = { + enable = true; + }; +} + diff --git a/modules/services/attic/default.nix b/modules/services/attic/default.nix new file mode 100644 index 0000000..a670b12 --- /dev/null +++ b/modules/services/attic/default.nix @@ -0,0 +1,57 @@ +{ + lib, + config, + ... +}: { + sops = { + secrets."attic/server_token" = {}; + secrets."cloudflare/r2/access_key" = {}; + secrets."cloudflare/r2/secret_key" = {}; + templates."attic-env".content = '' + ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=${config.sops.placeholder."attic/server_token"} + AWS_ACCESS_KEY_ID=${config.sops.placeholder."cloudflare/r2/access_key"} + AWS_SECRET_ACCESS_KEY=${config.sops.placeholder."cloudflare/r2/secret_key"} + ''; + }; + services = { + atticd = { + enable = true; + mode = "monolithic"; + environmentFile = config.sops.templates."attic-env".path; + settings = { + listen = "[::]:8080"; + api-endpoint = "https://cache.wanderingcrow.net/"; + jwt = {}; + chunking = { + nar-size-threshold = 64 * 1024; # 64 KiB + min-size = 16 * 1024; # 16 KiB + avg-size = 64 * 1024; # 64 KiB + max-size = 256 * 1024; # 256 KiB + }; + storage = { + type = "s3"; + region = ""; + bucket = "wce-attic-cache"; + endpoint = "https://68c4b3ab47c1a97037ab5a938f772d69.r2.cloudflarestorage.com"; + }; + }; + }; + nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "cache.wanderingcrow.net" = { + forceSSL = true; + extraConfig = '' + client_max_body_size 0; + ''; + useACMEHost = "cache.wanderingcrow.net"; + locations."/" = { + proxyPass = "http://localhost:8080"; + proxyWebsockets = true; + }; + }; + }; + }; + }; +} diff --git a/modules/services/bar-assistant/default.nix b/modules/services/bar-assistant/default.nix new file mode 100644 index 0000000..a631753 --- /dev/null +++ b/modules/services/bar-assistant/default.nix @@ -0,0 +1,109 @@ +let + volumePath = "/overseer/services"; +in + { + lib, + config, + ... + }: { + ########### + # SECRETS # + ########### + + sops = { + # Meilisearch secrets + secrets."meilisearch/masterkey" = {}; + templates."meilisearch-environment".content = '' + MEILI_MASTER_KEY=${config.sops.placeholder."meilisearch/masterkey"} + ''; + + # Bar Assistant secrets + templates."bar_assistant-env".content = '' + MEILISEARCH_KEY=${config.sops.placeholder."meilisearch/masterkey"} + ''; + }; + + systemd.tmpfiles.rules = [ + "d ${volumePath}/bar-assistant 770 33 33" + "d ${volumePath}/meilisearch" + ]; + + ########### + # Routing # + ########### + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "bar.wanderingcrow.net" = { + extraConfig = '' + allow 192.168.0.0/16; + allow 10.8.0.0/24; + allow 172.220.132.255; + deny all; + ''; + forceSSL = true; + useACMEHost = "bar.wanderingcrow.net"; + locations = { + "/search/" = { + proxyPass = "http://10.88.0.3:7700/"; + priority = 1; + }; + "/api/" = { + proxyPass = "http://10.88.0.4:8080/"; + priority = 1; + }; + "/" = { + proxyPass = "http://10.88.0.5:8080/"; + }; + }; + }; + }; + }; + + ########### + # Service # + ########### + + virtualisation.oci-containers = { + backend = "podman"; + containers = { + "meilisearch" = { + image = "getmeili/meilisearch:v1.8"; + volumes = ["${volumePath}/meilisearch:/meili_data"]; + extraOptions = ["--ip=10.88.0.3"]; + environmentFiles = [config.sops.templates."meilisearch-environment".path]; + environment = { + MEILI_ENV = "production"; + MEILI_NO_ANALYTICS = "true"; + }; + }; + "bar-assistant" = { + image = "barassistant/server:v4"; + volumes = ["${volumePath}/bar-assistant:/var/www/cocktails/storage/bar-assistant"]; + dependsOn = ["meilisearch"]; + extraOptions = ["--ip=10.88.0.4"]; + environmentFiles = [config.sops.templates."bar_assistant-env".path]; + environment = { + APP_URL = "https://bar.wanderingcrow.net/api"; + MEILISEARCH_HOST = "https://bar.wanderingcrow.net/search"; + CACHE_DRIVER = "file"; + SESSION_DRIVER = "file"; + ALLOW_REGISTRATION = "true"; + }; + }; + "salt-rim" = { + image = "barassistant/salt-rim:v3"; + dependsOn = ["bar-assistant"]; + extraOptions = ["--ip=10.88.0.5"]; + ports = ["3001:8080"]; + environment = { + API_URL = "https://bar.wanderingcrow.net/api"; + MEILIESEARCH_URL = "https://bar.wanderingcrow.net/search"; + }; + }; + }; + }; + } + diff --git a/modules/services/calibre/default.nix b/modules/services/calibre/default.nix new file mode 100644 index 0000000..7568cdd --- /dev/null +++ b/modules/services/calibre/default.nix @@ -0,0 +1,9 @@ +{ + config, + lib, + ... +}: { + services.calibre-web = { + enable = true; + }; +} diff --git a/modules/services/ferdium-server/default.nix b/modules/services/ferdium-server/default.nix new file mode 100644 index 0000000..5553464 --- /dev/null +++ b/modules/services/ferdium-server/default.nix @@ -0,0 +1,66 @@ +{ + lib, + config, + ... +}: let + volumePath = "/overseer/services"; +in { + systemd.tmpfiles.rules = [ + "d ${volumePath}/ferdium-server/data" + "d ${volumePath}/ferdium-server/app/recipes" + ]; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "ferdium.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "ferdium.wanderingcrow.net"; + locations = { + "/" = { + proxyPass = "http://10.88.0.13:3333"; + proxyWebsockets = true; + }; + }; + }; + }; + }; + virtualisation.oci-containers = { + backend = "podman"; + containers = { + "ferdium-api" = { + image = "ferdium/ferdium-server:latest"; + volumes = [ + "${volumePath}/ferdium-server/data:/data" + "${volumePath}/ferdium-server/app/recipes:/app/recipes" + ]; + extraOptions = ["--ip=10.88.0.13"]; + environment = { + NODE_ENV = "production"; + APP_URL = "ferdium.wanderingcrow.net"; + DB_CONNECTION = "sqlite"; + DB_HOST = "127.0.0.1"; + DB_PORT = "3306"; + DB_USER = "root"; + DB_PASSWORD = "password"; # Do I need to change this for sqlite I dont think so + DB_DATABASE = "ferdium"; + DB_SSL = "false"; + MAIL_CONNECTION = "smtp"; + SMTP_HOST = "127.0.0.1"; + SMTP_PORT = "2525"; + MAIL_SSL = "false"; + MAIL_USERNAME = "username"; + MAIL_PASSWORD = "password"; + MAIL_SENDER = "noreply@mail.wanderingcrow.net"; + IS_CREATION_ENABLED = "true"; + IS_DASHBOARD_ENABLED = "true"; + IS_REGISTRATION_ENABLED = "true"; + CONNECT_WITH_FRANZ = "false"; + DATA_DIR = "/data"; + JWT_USE_PEM = "true"; + }; + }; + }; + }; +} diff --git a/modules/services/frigate/default.nix b/modules/services/frigate/default.nix new file mode 100644 index 0000000..ff88b6f --- /dev/null +++ b/modules/services/frigate/default.nix @@ -0,0 +1,220 @@ +let + volumePath = "/overseer/services"; +in + { + pkgs, + lib, + config, + ... + }: let + frigateConfig = pkgs.writeText "config.yaml" (lib.generators.toYAML {} { + auth.reset_admin_password = true; # roll the admin password every restart, depend on user accounts for long-lived access + tls.enabled = false; # off because we're doing ssl through nginx + mqtt = { + # TODO: add mqtt broker + enabled = false; + }; + notifications = { + enabled = true; + email = "frigate@wanderingcrow.net"; + }; + ################### + # go2rtc restream # + ################### + go2rtc = { + streams = { + wce-0001 = [ + "rtsp://thingino:thingino@192.168.150.1:554/ch0" + ]; + wce-0001_sub = [ + "rtsp://thingino:thingino@192.168.150.1:554/ch1" + ]; + wce-0002 = [ + "rtsp://thingino:thingino@192.168.150.2:554/ch0" + ]; + wce-0002_sub = [ + "rtsp://thingino:thingino@192.168.150.2:554/ch1" + ]; + wce-0003 = [ + "rtsp://thingino:thingino@192.168.150.3:554/ch0" + ]; + wce-0003_sub = [ + "rtsp://thingino:thingino@192.168.150.3:554/ch1" + ]; + }; + }; + ############# + # Detectors # + ############# + detectors = { + ov_0 = { + type = "openvino"; + device = "CPU"; + }; + }; + model = { + width = 300; + height = 300; + input_tensor = "nhwc"; + input_pixel_format = "bgr"; + path = "/openvino-model/ssdlite_mobilenet_v2.xml"; + labelmap_path = "/openvino-model/coco_91cl_bkgr.txt"; + }; + objects = { + track = [ + "person" + "cat" + "car" + "dog" + ]; + }; + review = { + alerts = { + labels = [ + "person" + "cat" + ]; + }; + }; + #################### + # Data Persistence # + #################### + record = { + enabled = true; + retain.days = 0; # as per official documentation + alerts = { + retain.days = 14; + }; + detections = { + retain.days = 14; + }; + }; + ################# + # Camera config # + ################# + cameras = { + wce-0001 = { + ffmpeg = { + inputs = [ + { + path = "rtsp://127.0.0.1:8554/wce-0001"; + roles = ["record"]; + } + { + path = "rtsp://127.0.0.1:8554/wce-0001_sub"; + roles = ["detect"]; + } + ]; + }; + live.stream_name = "wce-0001_sub"; + motion = { + enabled = true; + mask = [ + "0,0,0.196,0.002,0.195,0.045,0,0.043" # timestamp + "0.898,0,0.896,0.045,1,0.048,0.999,0.002" # uptime + ]; + }; + detect.enabled = true; + }; + wce-0002 = { + ffmpeg = { + inputs = [ + { + path = "rtsp://127.0.0.1:8554/wce-0002"; + roles = ["record"]; + } + { + path = "rtsp://127.0.0.1:8554/wce-0002_sub"; + roles = ["detect"]; + } + ]; + }; + live.stream_name = "wce-0002_sub"; + motion = { + enabled = true; + mask = [ + "0,0,0.196,0.002,0.195,0.045,0,0.043" # timestamp + "0.898,0,0.896,0.045,1,0.048,0.999,0.002" # uptime + ]; + }; + detect.enabled = true; + }; + wce-0003 = { + ffmpeg = { + inputs = [ + { + path = "rtsp://127.0.0.1:8554/wce-0003"; + roles = ["record"]; + } + { + path = "rtsp://127.0.0.1:8554/wce-0003_sub"; + roles = ["detect"]; + } + ]; + }; + live.stream_name = "wce-0003_sub"; + motion = { + enabled = true; + mask = [ + "0,0,0.196,0.002,0.195,0.045,0,0.043" # timestamp + "0.898,0,0.896,0.045,1,0.048,0.999,0.002" # uptime + ]; + }; + detect.enabled = true; + }; + }; + }); + in { + sops = { + templates."frigate_env".content = '' + FRIGATE_JWT_SECRET=${config.sops.placeholder."frigate/jwt"} + ''; + secrets = { + "frigate/jwt" = {}; + }; + }; + systemd.tmpfiles.rules = [ + "d ${volumePath}/frigate" + "d ${volumePath}/frigate/media/frigate" + "d ${volumePath}/frigate/db" + "f ${volumePath}/frigate/db/frigate.db" + ]; + ########### + # Service # + ########### + + virtualisation.oci-containers = { + backend = "podman"; + containers = { + "frigate" = { + image = "ghcr.io/blakeblackshear/frigate:stable"; + environmentFiles = [config.sops.templates."frigate_env".path]; + volumes = [ + "/etc/localtime:/etc/localtime:ro" + "${volumePath}/frigate/media/frigate:/media/frigate" + "${frigateConfig}:/config/config.yaml:ro" + "${volumePath}/frigate/db/frigate.db:/config/frigate.db" + ]; + extraOptions = [ + "--shm-size=612m" + "--ip=10.88.0.10" + ]; + }; + }; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "frigate.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "frigate.wanderingcrow.net"; + locations."/" = { + proxyPass = "http://10.88.0.10:8971"; + proxyWebsockets = true; + }; + }; + }; + }; + } diff --git a/modules/services/grocy/default.nix b/modules/services/grocy/default.nix new file mode 100644 index 0000000..8e2d1b4 --- /dev/null +++ b/modules/services/grocy/default.nix @@ -0,0 +1,42 @@ +let + volumePath = "/overseer/services"; +in + { + lib, + config, + ... + }: { + systemd.tmpfiles.rules = [ + "d ${volumePath}/barcodebuddy" + ]; + + services.nginx.virtualHosts = { + "grocy.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "grocy.wanderingcrow.net"; + }; + "barcodebuddy.grocy.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "barcodebuddy.grocy.wanderingcrow.net"; + locations."/" = { + proxyPass = "http://10.88.0.11:80"; + proxyWebsockets = true; + }; + }; + }; + + services.grocy = { + enable = true; + hostName = "grocy.wanderingcrow.net"; + nginx.enableSSL = false; + }; + + virtualisation.oci-containers.containers = { + barcodebuddy = { + image = "f0rc3/barcodebuddy:latest"; + volumes = ["${volumePath}/barcodebuddy:/config"]; + + extraOptions = ["--ip=10.88.0.11"]; + }; + }; + } diff --git a/modules/services/homebox/default.nix b/modules/services/homebox/default.nix new file mode 100644 index 0000000..a4b80d3 --- /dev/null +++ b/modules/services/homebox/default.nix @@ -0,0 +1,35 @@ +{ + lib, + config, + ... +}: { + services = { + nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "homebox.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "homebox.wanderingcrow.net"; + locations."/" = { + extraConfig = '' + allow 192.168.0.0/16; + allow 10.8.0.0/24; + allow 172.220.132.255; + deny all; + ''; + proxyPass = "http://localhost:7745"; + proxyWebsockets = true; + }; + }; + }; + }; + + homebox = { + enable = true; + settings = { + HBOX_OPTIONS_ALLOW_REGISTRATION = "true"; + }; + }; + }; +} diff --git a/modules/services/homepage/default.nix b/modules/services/homepage/default.nix new file mode 100644 index 0000000..8121135 --- /dev/null +++ b/modules/services/homepage/default.nix @@ -0,0 +1,260 @@ +{ + lib, + inputs, + config, + ... +}: let + s = inputs.nix-secrets; +in { + # Homepage.dev secrets + sops = { + secrets = { + "homepage/openmeteo/lat" = {}; + "homepage/openmeteo/long" = {}; + "lubelogger/user" = {}; + "lubelogger/pass" = {}; + }; + templates."homepage-environment".content = '' + HOMEPAGE_VAR_LAT = ${config.sops.placeholder."homepage/openmeteo/lat"} + HOMEPAGE_VAR_LONG = ${config.sops.placeholder."homepage/openmeteo/long"} + HOMEPAGE_VAR_LUBELOGGERUSER = ${config.sops.placeholder."lubelogger/user"} + HOMEPAGE_VAR_LUBELOGGERPASS = ${config.sops.placeholder."lubelogger/pass"} + HOMEPAGE_ALLOWED_HOSTS = home.wanderingcrow.net + ''; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "home.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "home.wanderingcrow.net"; + locations."/" = { + extraConfig = '' + allow 192.168.0.0/16; + allow 10.8.0.0/24; + allow 172.220.134.108; + deny all; + ''; + proxyPass = "http://localhost:8089"; + proxyWebsockets = true; + }; + }; + }; + }; + + services = { + homepage-dashboard = { + enable = true; + listenPort = 8089; + environmentFile = config.sops.templates."homepage-environment".path; + settings = { + theme = "dark"; + }; + services = [ + { + "Services" = [ + { + "Garage" = { + icon = "https://garage.wanderingcrow.net/favicon.ico"; + href = "https://garage.wanderingcrow.net"; + description = "Vehicle management"; + widget = { + type = "lubelogger"; + url = "https://garage.wanderingcrow.net"; + username = "{{HOMEPAGE_VAR_LUBELOGGERUSER}}"; + password = "{{HOMEPAGE_VAR_LUBELOGGERPASS}}"; + }; + }; + } + ]; + } + ]; + widgets = [ + { + search = { + provider = "duckduckgo"; + target = "_blank"; + }; + } + { + openmeteo = { + timezone = "America/New_York"; + units = "imperial"; + cache = "5"; + latitude = "{{HOMEPAGE_VAR_LAT}}"; + longitude = "{{HOMEPAGE_VAR_LONG}}"; + }; + } + { + glances = { + url = "http://localhost:61208"; + version = 4; + disk = "/"; + label = "Overseer"; + }; + } + ]; + bookmarks = [ + { + WCE = [ + { + Grocy = [ + { + icon = "grocy.svg"; + href = "https://grocy.wanderingcrow.net"; + } + ]; + } + { + Homebox = [ + { + icon = "https://homebox.wanderingcrow.net/favicon.svg"; + href = "https://homebox.wanderingcrow.net"; + } + ]; + } + { + Bar = [ + { + icon = "https://bar.wanderingcrow.net/favicon.svg"; + href = "https://bar.wanderingcrow.net"; + } + ]; + } + ]; + } + { + "Day to Day" = [ + { + Messages = [ + { + icon = "google-messages.svg"; + href = "https://messages.google.com/web"; + } + ]; + } + { + YouTube = [ + { + icon = "youtube.svg"; + href = "https://youtube.com"; + } + ]; + } + { + "Proton Mail" = [ + { + icon = "proton-mail.svg"; + href = "https://mail.proton.me"; + } + ]; + } + { + Crunchyroll = [ + { + icon = "https://www.crunchyroll.com/build/assets/img/favicons/favicon-v2-32x32.png"; + href = "https://crunchyroll.com"; + } + ]; + } + { + Instagram = [ + { + icon = "instagram.svg"; + href = "https://instagram.com"; + } + ]; + } + { + Aetolia = [ + { + icon = "https://aetolia.com/wp-content/uploads/2020/04/favicon.ico"; + href = "https://aetolia.com"; + } + ]; + } + { + Amazon = [ + { + icon = "amazon.svg"; + href = "https://amazon.com"; + } + ]; + } + ]; + } + { + Work = [ + { + Jira = [ + { + icon = "jira.svg"; + href = "https://home.atlassian.com/"; + } + ]; + } + { + AWS = [ + { + icon = "aws.svg"; + href = "https://console.aws.amazon.com/"; + } + ]; + } + { + Email = [ + { + icon = "gmail.svg"; + href = "https://mail.google.com/mail/u/1/#inbox"; + } + ]; + } + { + Groups = [ + { + icon = "https://www.gstatic.com/images/branding/product/1x/groups_32dp.png"; + href = "https://groups.google.com/u/1/"; + } + ]; + } + ]; + } + { + Nix = [ + { + Search = [ + { + icon = "https://search.nixos.org/images/nix-logo.png"; + href = "https://search.nixos.org"; + } + ]; + } + { + "PR Tracker" = [ + { + href = "https://nixpk.gs/pr-tracker.html"; + } + ]; + } + { + "Home Manager Options" = [ + { + href = "https://home-manager-options.extranix.com/"; + } + ]; + } + { + "Nixpkgs Versions" = [ + { + href = "https://lazamar.co.uk/nix-versions/"; + } + ]; + } + ]; + } + ]; + }; + }; +} diff --git a/modules/services/lubelogger/default.nix b/modules/services/lubelogger/default.nix new file mode 100644 index 0000000..eedc10e --- /dev/null +++ b/modules/services/lubelogger/default.nix @@ -0,0 +1,66 @@ +let + volumePath = "/overseer/services"; +in + { + lib, + config, + ... + }: { + systemd.tmpfiles.rules = [ + "d ${volumePath}/lubelogger" + "d ${volumePath}/lubelogger/data" + "d ${volumePath}/lubelogger/keys" + ]; + ########### + # Service # + ########### + + sops = { + secrets = { + "lubelogger/user_hash" = {}; + "lubelogger/pass_hash" = {}; + }; + templates."lubelogger-env".content = '' + LC_ALL=en_US.UTF-8 + LANG=en_US.UTF-8 + MailConfig__EmailServer="" + MailConfig__EmailFrom="" + MailConfig__Port=587 + MailConfig__Username="" + MailConfig__Password="" + UserNameHash="${config.sops.placeholder."lubelogger/user_hash"}" + UserPasswordHash="${config.sops.placeholder."lubelogger/pass_hash"}" + LUBELOGGER_CUSTOM_WIDGETS=true + ''; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "garage.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "garage.wanderingcrow.net"; + locations."/" = { + proxyPass = "http://10.88.0.8:8080"; + proxyWebsockets = true; + }; + }; + }; + }; + + virtualisation.oci-containers = { + backend = "podman"; + containers = { + "lubelogger" = { + image = "ghcr.io/hargata/lubelogger:latest"; + extraOptions = ["--ip=10.88.0.8"]; + environmentFiles = [config.sops.templates."lubelogger-env".path]; + volumes = [ + "${volumePath}/lubelogger/data:/App/data" + "${volumePath}/lubelogger/keys:/root/.aspnet/DataProtection-Keys" + ]; + }; + }; + }; + } diff --git a/modules/services/matrix/default.nix b/modules/services/matrix/default.nix new file mode 100644 index 0000000..d3b86c7 --- /dev/null +++ b/modules/services/matrix/default.nix @@ -0,0 +1,86 @@ +{ + lib, + config, + ... +}: let + fqdn = "matrix.wanderingcrow.net"; + baseUrl = "https://${fqdn}"; + clientConfig."m.homeserver".base_url = baseUrl; + serverConfig."m.server" = "${fqdn}:443"; + mkWellKnown = data: '' + default_type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '${builtins.toJSON data}'; + ''; +in { + ############ + # Database # + ############ + services.postgresql = { + enable = true; + ensureUsers = [ + { + name = "matrix-synapse"; + ensureDBOwnership = true; + } + ]; + ensureDatabases = ["matrix-synapse"]; + }; + + services.nginx = { + enable = true; + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedProxySettings = true; + virtualHosts = { + "wanderingcrow.net" = { + forceSSL = lib.mkDefault true; + useACMEHost = lib.mkDefault "wanderingcrow.net"; + locations = { + "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; + "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; + }; + }; + "${fqdn}" = { + forceSSL = true; + useACMEHost = "${fqdn}"; + locations = { + "/".extraConfig = ''return 404;''; + "/_matrix".proxyPass = "http://localhost:8008"; + "/_synapse/client".proxyPass = "http://localhost:8008"; + }; + }; + }; + }; + + services.matrix-synapse = { + enable = true; + settings = { + server_name = "wanderingcrow.net"; + public_baseurl = baseUrl; + listeners = [ + { + port = 8008; + bind_addresses = ["::1"]; + type = "http"; + tls = false; + x_forwarded = true; + resources = [ + { + names = ["client" "federation"]; + compress = true; + } + ]; + } + ]; + database = { + name = "psycopg2"; + args = { + user = "matrix-synapse"; + database = "matrix-synapse"; + }; + }; + }; + }; +} diff --git a/modules/services/openhab/default.nix b/modules/services/openhab/default.nix new file mode 100644 index 0000000..73dac62 --- /dev/null +++ b/modules/services/openhab/default.nix @@ -0,0 +1,51 @@ +let + volumePath = "/overseer/services"; +in + { + lib, + config, + ... + }: { + systemd.tmpfiles.rules = [ + "d ${volumePath}/openhab openhab" + "d ${volumePath}/openhab/conf openhab" + "d ${volumePath}/openhab/userdata openhab" + "d ${volumePath}/openhab/addons openhab" + ]; + ########### + # Service # + ########### + + virtualisation.oci-containers = { + backend = "podman"; + containers."openhab" = { + image = "openhab/openhab:5.0.0.M1"; + extraOptions = ["--ip=10.88.0.9"]; + volumes = [ + "${volumePath}/openhab/conf:/openhab/conf" + "${volumePath}/openhab/userdata:/openhab/userdata" + "${volumePath}/openhab/addons:/openhab/addons" + ]; + }; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "openhab.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "openhab.wanderingcrow.net"; + locations."/" = { + extraConfig = '' + allow 192.168.0.0/16; + allow 10.8.0.0/24; + allow 172.220.132.255; + deny all; + ''; + proxyPass = "http://10.88.0.9:8080"; + }; + }; + }; + }; + } diff --git a/modules/services/the-nest/default.nix b/modules/services/the-nest/default.nix new file mode 100644 index 0000000..43efcb7 --- /dev/null +++ b/modules/services/the-nest/default.nix @@ -0,0 +1,24 @@ +{ + lib, + config, + inputs, + ... +}: { + services = { + nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "wanderingcrow.net" = { + default = true; + forceSSL = true; + useACMEHost = "wanderingcrow.net"; + locations."/" = { + root = inputs.the-nest.outputs.packages.x86_64-linux.default; + }; + }; + }; + }; + }; +} + diff --git a/modules/services/trilium/default.nix b/modules/services/trilium/default.nix new file mode 100644 index 0000000..c70352b --- /dev/null +++ b/modules/services/trilium/default.nix @@ -0,0 +1,30 @@ +{ + lib, + config, + pkgs, + ... +}: { + services = { + trilium-server = { + enable = true; + package = pkgs.trilium-next-server; + instanceName = "WanderingCrow"; + port = 8090; + }; + + nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "notes.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "notes.wanderingcrow.net"; + locations."/" = { + proxyPass = "http://127.0.0.1:8090"; + proxyWebsockets = true; + }; + }; + }; + }; + }; +} diff --git a/modules/services/umami/default.nix b/modules/services/umami/default.nix new file mode 100644 index 0000000..5344007 --- /dev/null +++ b/modules/services/umami/default.nix @@ -0,0 +1,71 @@ +let + volumePath = "/overseer/services"; +in + { + lib, + config, + ... + }: { + systemd.tmpfiles.rules = [ + "d ${volumePath}/umami" + ]; + ########### + # Service # + ########### + + sops = { + secrets = { + "umami/secret" = {}; + "umami/db_url" = {}; + "umami/db_pass" = {}; + }; + templates."umami-env".content = '' + APP_SECRET=${config.sops.placeholder."umami/secret"} + DATABASE_TYPE=postgresql + DATABASE_URL=${config.sops.placeholder."umami/db_url"} + ''; + templates."umami-db".content = '' + POSTGRES_DB=umami + POSTGRES_USER=umami + POSTGRES_PASSWORD=${config.sops.placeholder."umami/db_pass"} + ''; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "umami.wanderingcrow.net" = { + forceSSL = true; + useACMEHost = "umami.wanderingcrow.net"; + locations."/" = { + proxyPass = "http://10.88.0.6:3000"; + proxyWebsockets = true; + }; + locations."/script.js" = { + extraConfig = '' + deny 172.220.132.255; + ''; + }; + }; + }; + }; + + virtualisation.oci-containers = { + backend = "podman"; + containers = { + "umami" = { + image = "ghcr.io/umami-software/umami:postgresql-latest"; + dependsOn = ["umami-db"]; + extraOptions = ["--ip=10.88.0.6"]; + environmentFiles = [config.sops.templates."umami-env".path]; + }; + "umami-db" = { + image = "postgres:15-alpine"; + volumes = ["${volumePath}/umami:/var/lib/postgresql/data"]; + extraOptions = ["--ip=10.88.0.7"]; + environmentFiles = [config.sops.templates."umami-db".path]; + }; + }; + }; + }