diff --git a/constants.nix b/constants.nix index aeb5aea..5dfa26e 100644 --- a/constants.nix +++ b/constants.nix @@ -25,26 +25,23 @@ rec { subdomain = "f"; fqdn = subdomain + "." + domain; }; - librechat-oci = { - fqdn = "lc." + domain; - port = 3080; - }; - mailserver = rec { - subdomain = "mail"; - fqdn = subdomain + "." + domain; - }; miniflux = { fqdn = "rss." + domain; port = 8085; }; netdata = { - fqdn = "mon." + domain; + fqdn = "netdata." + intranet; port = 19999; }; open-webui-oci = { fqdn = "ai." + domain; port = 8083; }; + overleaf-oci = rec { + subdomain = "of"; + fqdn = subdomain + "." + domain; + port = 8081; + }; rss-bridge = rec { subdomain = "rss-bridge"; fqdn = subdomain + "." + domain; @@ -54,8 +51,12 @@ rec { port = 1200; }; vaultwarden = { - fqdn = "pw." + domain; + fqdn = "pw." + intranet; port = 8222; }; + webdav = { + fqdn = "dav." + intranet; + port = 8080; + }; }; } diff --git a/flake.lock b/flake.lock index b0a6409..da7918e 100644 --- a/flake.lock +++ b/flake.lock @@ -5199,11 +5199,11 @@ "stylix": "stylix_6" }, "locked": { - "lastModified": 1779222589, - "narHash": "sha256-pFlaPXus8e+mY9C7/xQhBwux6tPk5P30K2uaN2Qluh0=", + "lastModified": 1778016348, + "narHash": "sha256-C8PtC95r1KJync8qDEroIont1VT8tiwsjonYjwGLhbY=", "ref": "release-25.11", - "rev": "1ab817090ff5989578caefd8786e9450b37e3da5", - "revCount": 96, + "rev": "8ad8b1f633f6c3875032a0ead0e87255dff4ab3c", + "revCount": 57, "type": "git", "url": "https://git.sid.ovh/sid/synix.git" }, diff --git a/hosts/rx4/secrets/secrets.yaml b/hosts/rx4/secrets/secrets.yaml index 2b66560..0aa47f7 100644 --- a/hosts/rx4/secrets/secrets.yaml +++ b/hosts/rx4/secrets/secrets.yaml @@ -13,17 +13,12 @@ syncthing: gui-pw: ENC[AES256_GCM,data:mN4rxYr5DZgvbpIkwSFIuPvviJE=,iv:Kyl3mZFOejVwEwBCKteJQpgbCosREp9C4T4JYhWz6KQ=,tag:6myk9lr/44CH/hyUPgRH0Q==,type:str] forgejo-runner: token: ENC[AES256_GCM,data:DZgi6ocpV0MplgQ6Et85vHxmkMfC4qYbLLdyRuj/4z8tJauz1w6DUQ==,iv:+SZYsv6sDn2Nc1WxhTn0dJGN9nXYZw16/HVtXJGXpHc=,tag:8Oa5mC7cUy85+lXHbRcCcg==,type:str] +webdav: + user: ENC[AES256_GCM,data:vCLx,iv:Nra/FprNfd02HpvqOb5uYK+IGRFHhNwnFXWrX71c0C0=,tag:TjbKKOKBTq31o/5MxmqIsA==,type:str] + pass: ENC[AES256_GCM,data:jfIoob6R6OhqKa2EujRzTQbvIlA=,iv:HvB088H2Z2uLCveT4YfNEdkK5VU0lBFD5FrZhx79fg0=,tag:1RnrfeUEURx0C575GTxi9A==,type:str] vaultwarden: admin-token: ENC[AES256_GCM,data:HhD0xNZ/Ep7pCOX1j6p/M/ZZ3gs=,iv:7QT71KlYz+HQYBhiRavpiXS9sNS2PoJiM/WkxM3Hk/g=,tag:SYTRWpyA2+WMSMiRM8mvew==,type:str] smtp-password: ENC[AES256_GCM,data:eQo7op5+74EID6689hL0/J1pq2s=,iv:JqrEqxabWGydRuJJ/27e1q+4YnQhTQ1bKRSsOvjQ+bE=,tag:weqnrhqK+LGEfAacBcuPUA==,type:str] -hetzner-api-key: ENC[AES256_GCM,data:casjNOXzuQDWgnSFftbBMygA8kGpGiZDqup08faWO9kfjvgOyWOXeqPd2VA1ND8yfM2LvoLYvPs6gUWtni2ldQ==,iv:p2W24uhJgBvpi3g4+cHw0/XbbTM5oYCPHreMBUR4CNs=,tag:lpwjZGoJe/91+CHX/hAkKA==,type:str] -librechat: - jwt-secret: ENC[AES256_GCM,data:/OJr23Sw975byjyHN6yqWxuk5FeRfLdQYYOPYJeDHTjzq9X78c3VHqdvnN2a9ZUEtzRi1sx6YLIjNkxBkGbvuQ==,iv:2D0iBj2U3iy3JPtKZBWP5nCfmXMA2/pBhBKUD2f5DoM=,tag:0ZYNxBhUdCBOne0otcG2iQ==,type:str] - jwt-refresh-secret: ENC[AES256_GCM,data:qIaunHUMTUFyp88whrxe65eM3Mfi3EX0ieWOUCmYYojSKQQRudh8d4Cb1zMqPbXJLG3zqTVCaZl9xwQn5K4Z/g==,iv:k5+oSCd0TzdOmIUe8BQBesofjvjuRiPXdLT6H9yQf18=,tag:4wcJjX7MvJNx19PCxgqyhw==,type:str] - creds-key: ENC[AES256_GCM,data:EljwEqFByJaOjd8lRFGwo/FyXHUtl5an0xS1EjRe+kmpo5z4P33EUKbMeeIl69rEcziMHZQLiadzSEcS2cb2uA==,iv:sidBN6VTBeFhMUtN67HZuyofiXCeGFG4tuMRckLZv84=,tag:n7vI8LuPgER3J6r6Q6Jkjg==,type:str] - creds-iv: ENC[AES256_GCM,data:oc0sPm5RM/7AbH3vdDLJ2m0q6C7eAAME0GPbiojHZUspP8Cto5QX5WKnUjUVLLcvgK+t6pnu7BEmAuD3PLr11A==,iv:Z6XJmlqv0ULFiwqHyRO5v7lb/iyv4g9aSTV4xw9VTXU=,tag:7kptbQwc6lBZ70aXw7wOVA==,type:str] - meili-master-key: ENC[AES256_GCM,data:eugFl40a6Ks3ba8hcn83WS76AwA0TXkhu3K4gSrbNHtXRliLQCWhGTEvoaQSeb7whmpszh4zh8cKSxByBdhJiQ==,iv:rrWlcVyBlrE5dnBBFWjheIo6SgQTbkzqskGQvQczR+U=,tag:fjKOSVoPxomA3qUw+baV4w==,type:str] - requesty-key: ENC[AES256_GCM,data:vxr+m3c9qu6ChFvuAbBCFrneDP9xDIPJBRmB9diw5uSQD9XDl0IK954OzmMMXaSl2AeHgY8WiugvgvQjUwywjKG6TxxMEYMFsQkMpSnV7xHYv2MAE/TIC74CsHRL823MesUQ7agoIasFtjr+CnZ5RRUNHZOG,iv:pa64BT1yay5vYwn/XBdK7meYzOBk4M+MmgLzaHR5Hfw=,tag:L+lUPTE0ZI303jtVefIrvQ==,type:str] sops: age: - recipient: age19yeqvv28fgrtk6jsh3xyaf0lch86kna6rcz4dwe962yyyyevu30sx474xy @@ -44,7 +39,7 @@ sops: NE5yK3ZaOG5PdXNSUnlIUmFSSmRFancKk57hCmo79HvI3hzzgQvgOK7oK5/dcQR8 f3R4OGF5+212VXEHR/hAEbKzV7CY4y6HhFyrGZ9bUKm1RrxtnVqUyA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-25T18:14:59Z" - mac: ENC[AES256_GCM,data:eh/jcKrqyCTh+2n4phHQ2LKF71DaCDwrrfXms6HaD0ER4xVOkYERTe7IN4cX//qjY/91wSzAzwLg3yphWK4k920tiYTBog9LcWUz6l6X5lpmKHQp+vdoQH41WrA1ZgOcXzSfmZoblcD1qoJNCaHGt5N8hjXRcUc3lEqcPrdoC7A=,iv:8kBd9Daai3wJgzxONX4eIkeZLMzJO2DX439sBv/pER4=,tag:l8Q3gzMHoSTCdOqwzaKgCA==,type:str] + lastmodified: "2026-05-02T17:10:11Z" + mac: ENC[AES256_GCM,data:uf5TqZaevyUUjW6pM6K8c4CZFFdwTXFGIaHmYr5Q4XFR1uW3kBsVLeQKxq26duLuQ4UiZkUpW27a/PW797Z+iIpBdqbnoQ35q7RnOW+GpnAv8TaRW1PpqQ+JR3/R0LMXsi3cMt7ioG2ad1bIHztiNz+SmePiv3Yt9WxQ7PIqBdY=,iv:dAzuyKSo0OW+j02AH0chCdLBm7Wv6PZgqZrEWhEVnxQ=,tag:k6EKWHHY4fwTd03d4TVcNg==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1 diff --git a/hosts/rx4/services/default.nix b/hosts/rx4/services/default.nix index 8694146..df12843 100644 --- a/hosts/rx4/services/default.nix +++ b/hosts/rx4/services/default.nix @@ -10,20 +10,20 @@ inputs.clients.nixosModules.syncthing outputs.nixosModules.tailscale - # outputs.nixosModules.promtail ./forgejo.nix ./jirafeau.nix - ./librechat-oci.nix ./miniflux.nix ./netdata.nix ./nginx.nix + ./overleaf-oci.nix ./open-webui-oci.nix + ./print-server.nix ./rsshub-oci.nix - ./samba.nix ./vaultwarden.nix # ./alditalk-extender.nix # FIXME + # ./webdav.nix # FIXME ]; # bootstrap diff --git a/hosts/rx4/services/librechat-oci.nix b/hosts/rx4/services/librechat-oci.nix deleted file mode 100644 index 25149dc..0000000 --- a/hosts/rx4/services/librechat-oci.nix +++ /dev/null @@ -1,71 +0,0 @@ -{ - inputs, - constants, - config, - ... -}: - -let - inherit (constants.hosts.rx4) ip; - inherit (constants.services.librechat-oci) fqdn port; -in -{ - imports = [ - inputs.synix.nixosModules.librechat-oci - ]; - - services.librechat-oci = { - enable = true; - inherit port; - configFile = ./librechat.yaml; - externalUrl = "https://${fqdn}"; - environmentFile = config.sops.templates.librechat-env-file.path; - - environment = { - # ALLOW_REGISTRATION = "true"; - SEARXNG_INSTANCE_URL = "https://searxng.website/"; - }; - }; - - services.nginx.virtualHosts."${fqdn}" = { - useACMEHost = fqdn; - forceSSL = true; - listen = [ - { - addr = "${ip}:443"; - ssl = true; - } - ]; - locations."/" = { - proxyPass = "http://127.0.0.1:${toString port}"; - proxyWebsockets = true; - }; - }; - - security.acme.certs."${fqdn}" = { - domain = fqdn; - postRun = "systemctl restart podman-librechat.service"; - group = "nginx"; - }; - - sops = { - # generate with: - # openssl rand -hex 32 - secrets."librechat/jwt-secret" = { }; - secrets."librechat/jwt-refresh-secret" = { }; - secrets."librechat/creds-key" = { }; - secrets."librechat/creds-iv" = { }; - secrets."librechat/meili-master-key" = { }; - - secrets."librechat/requesty-key" = { }; - - templates.librechat-env-file.content = '' - JWT_SECRET=${config.sops.placeholder."librechat/jwt-secret"} - JWT_REFRESH_SECRET=${config.sops.placeholder."librechat/jwt-refresh-secret"} - CREDS_KEY=${config.sops.placeholder."librechat/creds-key"} - CREDS_IV=${config.sops.placeholder."librechat/creds-iv"} - MEILI_MASTER_KEY=${config.sops.placeholder."librechat/meili-master-key"} - REQUESTY_KEY=${config.sops.placeholder."librechat/requesty-key"} - ''; - }; -} diff --git a/hosts/rx4/services/librechat.yaml b/hosts/rx4/services/librechat.yaml deleted file mode 100644 index 327012a..0000000 --- a/hosts/rx4/services/librechat.yaml +++ /dev/null @@ -1,53 +0,0 @@ -version: 1.3.11 -cache: true - -interface: - customWelcome: "Such compose. Much yaml. Wow" - modelSelect: true - parameters: true - presets: true - prompts: - use: true - create: true - bookmarks: true - multiConvo: true - agents: true - fileSearch: true - webSearch: true - -# TODO: add cohere rerank -webSearch: - searchProvider: "searxng" - searxngInstanceUrl: "${SEARXNG_INSTANCE_URL}" - -endpoints: - agents: - disableBuilder: false - recursionLimit: 50 - maxRecursionLimit: 100 - maxCitations: 30 - maxCitationsPerFile: 7 - minRelevanceScore: 0.45 - capabilities: - - "deferred_tools" - - "execute_code" - - "file_search" - - "web_search" - - "artifacts" - - "actions" - - "context" - - "tools" - - "chain" - - custom: - - name: "Requesty" - apiKey: "${REQUESTY_KEY}" - baseURL: "https://router.requesty.ai/v1" - headers: - x-librechat-body-parentmessageid: "{{LIBRECHAT_BODY_PARENTMESSAGEID}}" - models: - default: ["meta-llama/llama-3-70b-instruct"] - fetch: true - titleConvo: true - titleModel: "meta-llama/llama-3-70b-instruct" - dropParams: ["stop"] diff --git a/hosts/rx4/services/netdata.nix b/hosts/rx4/services/netdata.nix index 956f612..30d720d 100644 --- a/hosts/rx4/services/netdata.nix +++ b/hosts/rx4/services/netdata.nix @@ -1,14 +1,12 @@ { config, constants, - pkgs, ... }: { services.netdata = { enable = true; - package = pkgs.netdata.override { withCloudUi = false; }; config.global = { "debug log" = "syslog"; "access log" = "syslog"; @@ -19,10 +17,6 @@ }; }; - services.journald.storage = "persistent"; - - users.users.netdata.extraGroups = [ "systemd-journal" ]; - sops = let owner = config.services.netdata.user; diff --git a/hosts/rx4/services/nginx.nix b/hosts/rx4/services/nginx.nix index cae8e31..c4c24af 100644 --- a/hosts/rx4/services/nginx.nix +++ b/hosts/rx4/services/nginx.nix @@ -7,8 +7,6 @@ let cfg = config.services.nginx; - - inherit (constants) domain; in { imports = [ @@ -36,21 +34,4 @@ in }; }; }; - - security.acme = { - acceptTerms = true; - defaults = { - email = "admin@${domain}"; - dnsProvider = "hetzner"; - credentialFiles = { - HETZNER_API_TOKEN_FILE = config.sops.secrets.hetzner-api-key.path; - }; - }; - }; - - sops.secrets.hetzner-api-key = { - mode = "0400"; - owner = "acme"; - group = "acme"; - }; } diff --git a/hosts/rx4/services/open-webui-oci.nix b/hosts/rx4/services/open-webui-oci.nix index f22297d..5c43197 100644 --- a/hosts/rx4/services/open-webui-oci.nix +++ b/hosts/rx4/services/open-webui-oci.nix @@ -2,19 +2,12 @@ inputs, constants, config, - lib, pkgs, ... }: -let - inherit (lib) getExe; -in { - imports = [ - inputs.synix.nixosModules.open-webui-oci - inputs.synix.nixosModules.mcpo - ]; + imports = [ inputs.synix.nixosModules.open-webui-oci ]; services.open-webui-oci = { enable = true; @@ -28,27 +21,6 @@ in }; }; - services.mcpo = { - enable = true; - package = pkgs.synix.mcpo; - port = 8765; - settings = { - mcpServers = { - fetcher-mcp = { - command = getExe pkgs.synix.fetcher-mcp; - }; - nixos = { - command = getExe pkgs.nix; - args = [ - "run" - "github:utensils/mcp-nixos" - "--" - ]; - }; - }; - }; - }; - # sops = { # secrets."open-webui-oci/stt-api-key" = { }; # secrets."open-webui-oci/tts-api-key" = { }; diff --git a/hosts/rx4/services/overleaf-oci.nix b/hosts/rx4/services/overleaf-oci.nix new file mode 100644 index 0000000..575012f --- /dev/null +++ b/hosts/rx4/services/overleaf-oci.nix @@ -0,0 +1,18 @@ +{ outputs, constants, ... }: + +let + inherit (constants.services.overleaf-oci) port subdomain; +in +{ + imports = [ outputs.nixosModules.overleaf-oci ]; + + services.overleaf-oci = { + enable = true; + inherit port; + reverseProxy = { + enable = true; + inherit subdomain; + forceSSL = false; + }; + }; +} diff --git a/hosts/rx4/services/print-server.nix b/hosts/rx4/services/print-server.nix new file mode 100644 index 0000000..64037fd --- /dev/null +++ b/hosts/rx4/services/print-server.nix @@ -0,0 +1,12 @@ +{ + inputs, + ... +}: + +{ + imports = [ + inputs.synix.nixosModules.print-server + ]; + + services.print-server.enable = true; +} diff --git a/hosts/rx4/services/samba.nix b/hosts/rx4/services/samba.nix deleted file mode 100644 index 2696005..0000000 --- a/hosts/rx4/services/samba.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ config, ... }: - -{ - services.samba = { - enable = true; - openFirewall = false; - nmbd.enable = false; - winbindd.enable = false; - settings = { - global = { - workgroup = "WORKGROUP"; - "server string" = config.networking.hostName; - security = "user"; - "map to guest" = "Bad User"; - "guest account" = "nobody"; - }; - share = { - path = "/home/sid"; - browseable = "yes"; - "read only" = "yes"; - "guest ok" = "yes"; - "force user" = "sid"; - "directory mask" = "0750"; - }; - }; - }; -} diff --git a/hosts/rx4/services/vaultwarden.nix b/hosts/rx4/services/vaultwarden.nix index d9f8092..6f00505 100644 --- a/hosts/rx4/services/vaultwarden.nix +++ b/hosts/rx4/services/vaultwarden.nix @@ -6,7 +6,6 @@ let inherit (constants) domain; - inherit (constants.hosts.rx4) ip; inherit (constants.services.vaultwarden) fqdn port; in { @@ -22,52 +21,21 @@ in environmentFile = [ config.sops.templates."vaultwarden/env-file".path ]; config = { - ENABLE_WEBSOCKET = true; SIGNUPS_ALLOWED = false; SMTP_FROM = "vaultwarden@${domain}"; SMTP_FROM_NAME = "${domain} Vaultwarden server"; - SMTP_HOST = constants.services.mailserver.fqdn; - SMTP_PORT = 465; - SMTP_SECURITY = "force_tls"; + SMTP_HOST = constants.hosts.sid.ip; + SMTP_PORT = 587; + SMTP_SECURITY = "starttls"; SMTP_USERNAME = "vaultwarden@${domain}"; - ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_ADDRESS = "0.0.0.0"; ROCKET_PORT = port; ROCKET_LOG = "critical"; }; }; - services.nginx.virtualHosts."${fqdn}" = { - useACMEHost = "pw-custom"; - forceSSL = true; - listen = [ - { - addr = "${ip}:443"; - ssl = true; - } - ]; - locations = { - "/" = { - proxyPass = "http://127.0.0.1:${toString port}"; - }; - "= /notifications/alerts" = { - proxyPass = "http://127.0.0.1:${toString port}"; - proxyWebsockets = true; - }; - "= /notifications/hub" = { - proxyPass = "http://127.0.0.1:${toString port}"; - proxyWebsockets = true; - }; - }; - }; - - security.acme.certs."pw-custom" = { - domain = fqdn; - postRun = "systemctl restart vaultwarden.service"; - group = "nginx"; - }; - sops = let owner = config.users.users.vaultwarden.name; diff --git a/hosts/rx4/services/webdav.nix b/hosts/rx4/services/webdav.nix new file mode 100644 index 0000000..46d01a9 --- /dev/null +++ b/hosts/rx4/services/webdav.nix @@ -0,0 +1,86 @@ +{ constants, config, ... }: + +# FIXME: floccus throws error: NetworkError when attempting to fetch resource. + +let + cfg = config.services.webdav; + + inherit (constants.services.webdav) fqdn port; +in +{ + services.webdav = { + enable = true; + environmentFile = config.sops.templates."webdav/env-file".path; + + settings = { + inherit port; + address = "127.0.0.1"; + prefix = "/"; + directory = "/srv/webdav"; + users = [ + { + username = "{env}WEBDAV_USER"; + password = "{env}WEBDAV_PASS"; + permissions = "CRUD"; + } + ]; + }; + }; + + systemd.tmpfiles.rules = [ + "d ${cfg.settings.directory} 0750 ${cfg.user} ${cfg.group} -" + ]; + + networking.firewall.allowedTCPPorts = [ port ]; + + services.nginx = { + enable = true; + virtualHosts."${fqdn}" = { + listen = [ + { + addr = "0.0.0.0"; + inherit port; + } + ]; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + extraConfig = '' + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PROPFIND, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Depth' always; + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PROPFIND, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Depth'; + return 204; + } + ''; + }; + }; + }; + + sops = + let + owner = cfg.user; + group = cfg.group; + mode = "0400"; + in + { + secrets = { + "webdav/user" = { + inherit owner group mode; + }; + "webdav/pass" = { + inherit owner group mode; + }; + }; + templates."webdav/env-file" = { + inherit owner group mode; + content = '' + WEBDAV_USER=${config.sops.placeholder."webdav/user"} + WEBDAV_PASS=${config.sops.placeholder."webdav/pass"} + ''; + }; + }; +} diff --git a/hosts/sid/secrets/secrets.yaml b/hosts/sid/secrets/secrets.yaml index f94edbf..8fb0e4a 100644 --- a/hosts/sid/secrets/secrets.yaml +++ b/hosts/sid/secrets/secrets.yaml @@ -35,7 +35,6 @@ radicale: step-ca: password: ENC[AES256_GCM,data:8/6NA3WpII0LmDOp5ISnHKeaXn5LM4gpiI47JTso23c=,iv:fi2eMGG1lOwdK5+98Hp7vZ101GKRip5Xgq9k+vnC9yI=,tag:oENvvsEbKSHFfLoXcJlPkg==,type:str] intermediate-key: ENC[AES256_GCM,data:yGZLSd7ydx9wNFpWWPcyUBwZQZbyziGleCWSxurFniBCauw2h4hcPc4c4I/7cjl1vRUv41WfzWu1PtXnZ3lNHOC6tTbiikHFBgGiHk2Lhddx+NESUWmgNiejJR/UDW4T25W9OHxwLCV9pmHf4fjyT/REymGIB7kbcRryWqcWtoZWYaL7JooJornm5mMU1Be+MCfxusTGQA4gQsT5/bu20iEGPwgY3fEgZLQWzKFI2kD2lYlMC8CRxoZO32uTizzooW1+zKng1qSZ7aobFJsbSKRYpYDv9Vvfwltcczb+xo+yZL3pfoEiqAxPzeG/48lRVNf1nftM5esBRGIIPr9BV9+7fbe5DFbSRDtAWspEnp9R5ENj1rbNint/fjCcStg3OfFMdv6N8cQyIpQyHCiBLiG4z+xyFcn0iW4=,iv:BhUoeaoetI5vJk9wOHhBI2ebHWCPeXz8U2ta/xEeUxM=,tag:7xg5ilOSJP1rFlSmmZVZUg==,type:str] -hetzner-api-key: ENC[AES256_GCM,data:NhgWjitvgJrcBEDSkZH0S0VmaW37NupkiEUcQDZe/6oYyrE/VgEwrGSag/s2Fgv6uHmSsdbv1vqdc0iDO8GJ8w==,iv:ChEicL0jtjQrgn8CCUnrzErRr3YVdDhMbvcIlI3t7H8=,tag:cjjbEEYqEyNa5qDZCytjxw==,type:str] sops: age: - recipient: age19yeqvv28fgrtk6jsh3xyaf0lch86kna6rcz4dwe962yyyyevu30sx474xy @@ -56,7 +55,7 @@ sops: RzhnczA0S1pxcXZncGpWVHNYQW96L28K+ytH3PPyg4+wibpAQhp02RiSfZ83EDRB UJ8UV1d+51D0e2A1sI95r2AzDj4jfwUnI+LYDPC/qEpsu5LFLGVyeg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-22T19:19:21Z" - mac: ENC[AES256_GCM,data:hOtmWizEaIcybM14UEDsXw4GNQZob5SoFn49bWeccxA3dkGlYl67kVkDJGg0cQIO1qr/vGcZ8h/OmnOxU3geP0DaflG0h1/40lDQ3+E6BTb6HP2JmhgEmlRBRBdv87cRDHnDytBzcWARTvff3SsP2J2pLpLBTDiihlaZaiQYtgU=,iv:TvFpvcTydXO3fbh5x9ZXIOtMChlE7WXl2Xx2a9ujh00=,tag:XHvsZh6r9fzbbYFWWQyI5g==,type:str] + lastmodified: "2026-05-02T17:10:22Z" + mac: ENC[AES256_GCM,data:f4KQ26/zvg2nLLeW5qVeI8uH2GmPpJUKohNu68nEiIjP5AT53zjBaGoLOTGl9+oVRomSOGZtLGkJGaExB6tLMon5HN6xkQbugqvq08UkZ7FnR1Sa8/OtTr/+eexPNzF8VSdZE2TZCboUSQODV8+0Cy5T918g5kedxnT62SyY4As=,iv:P4TnpJvHwnZPl7kRNjv9d1WLZP9J0sg6R3KbdDMJqyc=,tag:ylYOcg6825jT29lWUaFRYA==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1 diff --git a/hosts/sid/services/coredns.nix b/hosts/sid/services/coredns.nix new file mode 100644 index 0000000..c7af795 --- /dev/null +++ b/hosts/sid/services/coredns.nix @@ -0,0 +1,37 @@ +{ constants, ... }: + +{ + services.resolved.enable = false; + networking.resolvconf.enable = false; + + networking.nameservers = [ "127.0.0.1" ]; + + services.coredns = { + enable = true; + config = with constants; '' + .:53 { + bind 0.0.0.0 + hosts { + ${hosts.sid.ip} ${ca-fqdn} + + ${hosts.rx4.ip} rx4.tail + ${hosts.sid.ip} sid.tail + ${hosts.vde.ip} vde.tail + + ${hosts.sid.ip} ${services.netdata.fqdn} + ${hosts.sid.ip} ${services.vaultwarden.fqdn} + ${hosts.sid.ip} ${services.webdav.fqdn} + + fallthrough + } + forward . 1.1.1.1 8.8.8.8 + cache 30 + log + errors + } + ''; + }; + + networking.firewall.allowedUDPPorts = [ 53 ]; + networking.firewall.allowedTCPPorts = [ 53 ]; +} diff --git a/hosts/sid/services/default.nix b/hosts/sid/services/default.nix index ee63f99..c1079d8 100644 --- a/hosts/sid/services/default.nix +++ b/hosts/sid/services/default.nix @@ -9,9 +9,8 @@ inputs.synix.nixosModules.openssh outputs.nixosModules.tailscale - # outputs.nixosModules.loki - # outputs.nixosModules.promtail + ./coredns.nix ./headscale.nix ./mailserver.nix ./matrix-synapse.nix @@ -19,5 +18,6 @@ ./nginx.nix ./radicale.nix ./rss-bridge.nix + ./step-ca.nix ]; } diff --git a/hosts/sid/services/headscale.nix b/hosts/sid/services/headscale.nix index 0d4a03f..6c7148f 100644 --- a/hosts/sid/services/headscale.nix +++ b/hosts/sid/services/headscale.nix @@ -1,6 +1,5 @@ { inputs, - constants, ... }: @@ -25,12 +24,5 @@ enable = true; subdomain = "hs"; }; - settings.dns.extra_records = [ - { - name = constants.services.vaultwarden.fqdn; - type = "A"; - value = constants.hosts.rx4.ip; - } - ]; }; } diff --git a/hosts/sid/services/mailserver.nix b/hosts/sid/services/mailserver.nix index c70433e..f3af274 100644 --- a/hosts/sid/services/mailserver.nix +++ b/hosts/sid/services/mailserver.nix @@ -1,21 +1,15 @@ -{ inputs, constants, ... }: +{ inputs, config, ... }: -let - inherit (constants.services.mailserver) subdomain; -in { imports = [ inputs.synix.nixosModules.mailserver ]; mailserver = { enable = true; - inherit subdomain; stateVersion = 3; + localDnsResolver = !config.services.coredns.enable; accounts = { sid = { - aliases = [ - "admin" - "postmaster" - ]; + aliases = [ "postmaster" ]; }; vaultwarden = { }; }; diff --git a/hosts/sid/services/netdata.nix b/hosts/sid/services/netdata.nix index 6733c2a..005f9e1 100644 --- a/hosts/sid/services/netdata.nix +++ b/hosts/sid/services/netdata.nix @@ -1,37 +1,18 @@ { config, - constants, - lib, pkgs, ... }: let email = "sid@${config.networking.domain}"; - - netdata-dashboard = pkgs.stdenvNoCC.mkDerivation { - pname = "netdata-dashboard"; - version = "2.31.0"; - - src = pkgs.fetchurl { - url = "https://github.com/netdata/dashboard/releases/download/v2.31.0/dashboard.tar.gz"; - hash = "sha256-n7M7Y8LIb4tbgQ8wQIr5bMKxLT5fPDID5LnX47ayH/o="; - }; - - dontUnpack = true; - - installPhase = '' - mkdir -p $out - tar -xzf $src --strip-components=1 -C $out - ''; - - meta.license = lib.licenses.gpl3Only; - }; in { services.netdata = { enable = true; - package = pkgs.netdata.override { withCloudUi = false; }; + package = pkgs.netdata.override { + withCloudUi = true; + }; config.global = { "debug log" = "syslog"; "access log" = "syslog"; @@ -55,47 +36,6 @@ in NETDATA_USER_CONFIG_DIR = "/etc/netdata/conf.d"; }; - services.nginx.virtualHosts."${constants.services.netdata.fqdn}" = { - useACMEHost = constants.services.netdata.fqdn; - forceSSL = true; - listen = [ - { - addr = "${constants.hosts.sid.ip}:443"; - ssl = true; - } - ]; - - locations."/" = { - root = netdata-dashboard; - tryFiles = "$uri $uri/ /index.html"; - }; - - locations."~ ^/(api|v[0-9]+|netdata.conf|registry|stream|version.txt)(/|$)" = { - proxyPass = "http://127.0.0.1:${toString constants.services.netdata.port}"; - recommendedProxySettings = true; - }; - - locations."~ ^/host/" = { - proxyPass = "http://127.0.0.1:${toString constants.services.netdata.port}"; - recommendedProxySettings = true; - }; - }; - - security.acme = { - acceptTerms = true; - certs."${constants.services.netdata.fqdn}" = { - domain = constants.services.netdata.fqdn; - webroot = lib.mkForce null; - dnsProvider = "hetzner"; - credentialFiles.HETZNER_API_TOKEN_FILE = config.sops.secrets.hetzner-api-key.path; - group = "nginx"; - }; - }; - - services.journald.storage = "persistent"; - - users.users.netdata.extraGroups = [ "systemd-journal" ]; - sops = let owner = config.services.netdata.user; @@ -104,12 +44,6 @@ in restartUnits = [ "netdata.service" ]; in { - secrets.hetzner-api-key = { - inherit mode; - owner = "acme"; - group = "acme"; - }; - secrets."netdata/stream/rx4/uuid" = { inherit owner @@ -131,7 +65,6 @@ in [${config.sops.placeholder."netdata/stream/rx4/uuid"}] enabled = yes default history = 3600 - allow from = * ''; }; }; diff --git a/hosts/sid/services/nginx.nix b/hosts/sid/services/nginx.nix index 0844781..1c2f432 100644 --- a/hosts/sid/services/nginx.nix +++ b/hosts/sid/services/nginx.nix @@ -56,6 +56,15 @@ in address = constants.hosts.rx4.ip; port = constants.services.miniflux.port; }; + virtualHosts."${constants.services.netdata.fqdn}" = { + useACMEHost = "sid-internal"; + forceSSL = ssl; + locations."/" = { + # proxyPass = "http://${constants.hosts.sid.ip}:${toString constants.services.netdata.port}"; + proxyPass = "http://127.0.0.1:${toString constants.services.netdata.port}"; + proxyWebsockets = true; + }; + }; virtualHosts."${constants.services.open-webui-oci.fqdn}" = mkVirtualHost { inherit ssl; address = constants.hosts.rx4.ip; @@ -68,11 +77,33 @@ in error_log /var/log/nginx/open-webui-error.log debug; ''; }; + virtualHosts."${constants.services.overleaf-oci.fqdn}" = mkVirtualHost { + inherit ssl; + address = constants.hosts.rx4.ip; + port = constants.services.overleaf-oci.port; + }; virtualHosts."${constants.services.rsshub-oci.fqdn}" = mkVirtualHost { inherit ssl; address = constants.hosts.rx4.ip; port = constants.services.rsshub-oci.port; }; + virtualHosts."${constants.services.vaultwarden.fqdn}" = { + useACMEHost = "sid-internal"; + forceSSL = ssl; + locations = { + "/" = { + proxyPass = "http://${constants.hosts.rx4.ip}:${toString constants.services.vaultwarden.port}"; + }; + }; + }; + virtualHosts."${constants.services.webdav.fqdn}" = { + useACMEHost = "sid-internal"; + forceSSL = ssl; + locations."/" = { + proxyPass = "http://${constants.hosts.rx4.ip}:${toString constants.services.webdav.port}"; + proxyWebsockets = true; + }; + }; # FIXME # virtualHosts."print.sid.ovh" = { # enableACME = true; diff --git a/hosts/sid/services/step-ca.nix b/hosts/sid/services/step-ca.nix new file mode 100644 index 0000000..d3abb11 --- /dev/null +++ b/hosts/sid/services/step-ca.nix @@ -0,0 +1,108 @@ +{ + constants, + config, + pkgs, + ... +}: + +let + cfg = config.services.step-ca; +in +{ + services.step-ca = { + enable = true; + address = "0.0.0.0"; + port = 8443; + openFirewall = true; + intermediatePasswordFile = config.sops.secrets."step-ca/password".path; + # nix-shell -p step-cli --run "step ca init" + settings = { + # FIXME: nix-store paths do not work + # root = ../../../certs/root_ca.crt; + # crt = ../../../certs/intermediate_ca.crt; + # FIXME: not reproducible + root = "/var/lib/step-ca/certs/root_ca.crt"; + crt = "/var/lib/step-ca/certs/intermediate_ca.crt"; + key = config.sops.secrets."step-ca/intermediate-key".path; + dnsNames = [ + constants.ca-fqdn + constants.hosts.sid.ip + ]; + logger = { + format = "text"; + }; + db = { + type = "badgerv2"; + dataSource = "/var/lib/step-ca/db"; + }; + authority = { + provisioners = [ + { + type = "ACME"; + name = "acme"; + } + { + type = "JWK"; + name = "sid@sid.ovh"; + key = { + use = "sig"; + kty = "EC"; + kid = "w3fV4U-frlyTnBMg4yNYrLsn8_mY98H8HthoscpoVrg"; + crv = "P-256"; + alg = "ES256"; + x = "KZCDecn4sb87T3UO6JsIzJVtr4Aa0UcYzYDNBUM6F7M"; + y = "CbGHn9tXQbV0Ur2VuXITLnWgfxCRmKEoUdMUmrP9Qkw"; + }; + encryptedKey = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjYwMDAwMCwicDJzIjoiZS1MUDhDYlE4dzVuMF9nUGhXOWtGdyJ9.rgsqo58rJFWaociSqiPg3E1alAeqoHWubJi4n2uoUFYp3YTWaYZzqA.6P6oimHsKGdCWruo.fNaDr50IXCtCe7W7VIXuS3rlfin_R0nogNpIJ9C6szYg8k10UylircUs14Zl1EHQ9lFeJovb1y1uljzBajMGkOAGlMvashrphVkXiSxHWKDhzbrItJx3qChLtSLJJtXiXPbJQKCAeBjztqPuTw6dI4Z6IR9---kiTvzF6I9KE8afGFlMSubGjr9FnqgiOb2JiZuTfcBGDx78puxdWzUrEEVlliHdv2agbKhY0b13x-obaTIWwlqLFbasv7kPneJ8Ggp7IHHr5uDcUrqVKkTfBrD0lelXm6SwJTHGMkty6inlwSflT9mxvkNq7OGV9triPQc8AGVv0c7t7dHoX_E.tSjJqttCS6zLI_-7zPdXNQ"; + } + ]; + }; + tls = { + cipherSuites = [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ]; + renegotiation = false; + }; + }; + }; + + environment.systemPackages = [ + pkgs.step-cli + ]; + + systemd.tmpfiles.rules = [ + "d /var/lib/acme/acme-challenge 0755 acme nginx" + ]; + + security.acme = { + certs."sid-internal" = { + # domain = constants.intranet; + domain = constants.services.vaultwarden.fqdn; + extraDomainNames = [ + constants.services.netdata.fqdn + # constants.services.vaultwarden.fqdn + constants.services.webdav.fqdn + ]; + server = "https://${constants.ca-fqdn}:${toString cfg.port}/acme/acme/directory"; + group = "nginx"; + }; + }; + + sops = + let + owner = "step-ca"; + group = "step-ca"; + mode = "0400"; + in + { + secrets = { + "step-ca/password" = { + inherit owner group mode; + }; + "step-ca/intermediate-key" = { + inherit owner group mode; + }; + }; + }; +} diff --git a/modules/nixos/common/default.nix b/modules/nixos/common/default.nix index 71660e5..0415b9f 100644 --- a/modules/nixos/common/default.nix +++ b/modules/nixos/common/default.nix @@ -5,6 +5,10 @@ ./nix.nix ./overlays.nix + ../pki + inputs.synix.nixosModules.device.server ]; + + nixpkgs.config.allowUnfree = true; } diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index d3511ee..1028fdf 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -5,9 +5,9 @@ forgejo = import ./forgejo; forgejo-runner = import ./forgejo-runner; gnome = import ./gnome; - loki = import ./loki; monero = import ./monero; - promtail = import ./promtail; + overleaf-oci = import ./overleaf-oci; + pki = import ./pki; rsshub-oci = import ./rsshub-oci; tailscale = import ./tailscale; xfce = import ./xfce; diff --git a/modules/nixos/loki/dashboards/logs.json b/modules/nixos/loki/dashboards/logs.json deleted file mode 100644 index 2009e52..0000000 --- a/modules/nixos/loki/dashboards/logs.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Graphics --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 1, - "links": [], - "panels": [ - { - "datasource": { - "type": "loki", - "uid": "loki" - }, - "gridPos": { - "h": 24, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 1, - "options": { - "dedupStrategy": "none", - "enableLogDetails": true, - "prettifyLogMessage": false, - "showCommonLabels": false, - "showLabels": false, - "showTime": true, - "sortOrder": "Descending", - "wrapLogMessage": false - }, - "targets": [ - { - "datasource": { - "type": "loki", - "uid": "Loki" - }, - "expr": "{job=\"systemd-journal\"}", - "refId": "A" - } - ], - "title": "System Logs", - "type": "logs" - } - ], - "schemaVersion": 38, - "style": "dark", - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "System Logs", - "uid": "system-logs", - "version": 1 -} diff --git a/modules/nixos/loki/default.nix b/modules/nixos/loki/default.nix deleted file mode 100644 index e5fdd14..0000000 --- a/modules/nixos/loki/default.nix +++ /dev/null @@ -1,115 +0,0 @@ -{ - services.loki = { - enable = true; - configuration = { - auth_enabled = false; - - server = { - http_listen_address = "0.0.0.0"; - http_listen_port = 3100; - grpc_listen_port = 9096; - }; - - common = { - ring = { - instance_addr = "127.0.0.1"; - kvstore.store = "inmemory"; - }; - replication_factor = 1; - path_prefix = "/var/lib/loki"; - }; - - ingester = { - wal = { - enabled = true; - dir = "/var/lib/loki/wal"; - }; - chunk_encoding = "snappy"; - chunk_idle_period = "30m"; - max_chunk_age = "2h"; - chunk_target_size = 1572864; - chunk_block_size = 262144; - }; - - limits_config = { - reject_old_samples = true; - reject_old_samples_max_age = "168h"; - ingestion_rate_mb = 10; - ingestion_burst_size_mb = 20; - per_stream_rate_limit = "3MB"; - per_stream_rate_limit_burst = "15MB"; - max_line_size = "256KB"; - }; - - schema_config = { - configs = [ - { - from = "2026-01-01"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - ]; - }; - - storage_config = { - filesystem = { - directory = "/var/lib/loki/chunks"; - }; - }; - - compactor = { - working_directory = "/var/lib/loki/compactor"; - compaction_interval = "10m"; - retention_enabled = true; - retention_delete_delay = "2h"; - retention_delete_worker_count = 150; - delete_request_store = "filesystem"; - }; - }; - }; - - services.grafana = { - enable = true; - settings = { - server = { - http_addr = "0.0.0.0"; - http_port = 3003; - }; - "auth.anonymous" = { - enabled = true; - org_name = "Main Org."; - org_role = "Admin"; - }; - }; - - provision = { - enable = true; - datasources.settings = { - apiVersion = 1; - datasources = [ - { - name = "Loki"; - type = "loki"; - access = "proxy"; - url = "http://127.0.0.1:3100"; - isDefault = true; - uid = "loki"; - } - ]; - }; - dashboards.settings.providers = [ - { - name = "default"; - options.path = ./dashboards; - } - ]; - }; - }; - - networking.firewall.allowedTCPPorts = [ 3100 ]; -} diff --git a/modules/nixos/overleaf-oci/default.nix b/modules/nixos/overleaf-oci/default.nix new file mode 100644 index 0000000..6be248b --- /dev/null +++ b/modules/nixos/overleaf-oci/default.nix @@ -0,0 +1,257 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.overleaf-oci; + domain = config.networking.domain; + subdomain = cfg.reverseProxy.subdomain; + fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain; + + mongodbInitReplicaSet = ./mongodb-init-replica-set.js; + + images = { + # https://hub.docker.com/r/sharelatex/sharelatex + sharelatex = pkgs.dockerTools.pullImage { + imageName = "sharelatex/sharelatex"; + imageDigest = "sha256:fa5e5a049721b0973aa6ddabd15cb04da2d492f38c685fda0805dab97d4f3c8a"; + hash = "sha256-2Om6b+xPcBFObMKAlZ+qsvPw1xd8B/8ODyI5dsWoaQA="; + finalImageName = "sharelatex/sharelatex"; + finalImageTag = "6.1.2"; + }; + # https://hub.docker.com/_/mongo + mongo = pkgs.dockerTools.pullImage { + imageName = "mongo"; + imageDigest = "sha256:ce32a4b67580c982e2020b07d4ffafdbd9ce474088434294d89c6bd9257f7788"; + hash = "sha256-NtMSeH5hYD69uF7gZWPppxoI9esyPTfxaw50yh0ChpY="; + finalImageName = "mongo"; + finalImageTag = "8.3.1"; + }; + # https://hub.docker.com/_/redis + redis = pkgs.dockerTools.pullImage { + imageName = "redis"; + imageDigest = "sha256:0c341492924cad6f5483f9133e43bd6c51ecdecbcadfac5b51657393b6a7936c"; + hash = "sha256-nU5+UdvA+29sbr7dAD2jpKYACxYb3BfStlOE/25ET+w="; + finalImageName = "redis"; + finalImageTag = "8.6.3"; + }; + }; + + defaultEnv = { + EMAIL_CONFIRMATION_DISABLED = "true"; + ENABLED_LINKED_FILE_TYPES = "project_file,project_output_file"; + ENABLE_CONVERSIONS = "true"; + OVERLEAF_APP_NAME = "Overleaf Community Edition"; + OVERLEAF_MONGO_URL = "mongodb://mongo/sharelatex"; + OVERLEAF_REDIS_HOST = "redis"; + REDIS_HOST = "redis"; + }; + + inherit (lib) + mkEnableOption + mkIf + mkOption + mkOverride + optional + types + ; + inherit (lib.utils) + mkReverseProxyOption + mkVirtualHost + ; +in +{ + options.services.overleaf-oci = { + enable = mkEnableOption "Overleaf service stack with Podman"; + port = mkOption { + type = types.port; + default = 80; + description = "The port Overleaf will listen on."; + }; + environment = mkOption { + type = types.attrsOf types.str; + default = { }; + description = "Extra environment variables for Overleaf."; + }; + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = "Environment file for secrets."; + }; + reverseProxy = mkReverseProxyOption "Overleaf" "overleaf"; + }; + + config = mkIf cfg.enable { + virtualisation.podman = { + enable = true; + autoPrune.enable = true; + dockerCompat = true; + }; + + services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable { + "${fqdn}" = mkVirtualHost { + inherit (cfg) port; + ssl = cfg.reverseProxy.forceSSL; + }; + }; + + networking.firewall.interfaces = + let + matchAll = if !config.networking.nftables.enable then "podman+" else "podman*"; + in + { + "${matchAll}".allowedUDPPorts = [ 53 ]; + }; + + virtualisation.oci-containers.backend = "podman"; + + virtualisation.oci-containers.containers = { + overleaf-mongo = { + image = with images.mongo; imageName + ":" + imageTag; + imageFile = images.mongo; + environment = { + MONGO_INITDB_DATABASE = "sharelatex"; + }; + volumes = [ + "overleaf_mongo-data:/data/db:rw" + "${mongodbInitReplicaSet}:/docker-entrypoint-initdb.d/mongodb-init-replica-set.js:rw" + ]; + cmd = [ + "--replSet" + "overleaf" + ]; + log-driver = "journald"; + extraOptions = [ + "--network-alias=mongo" + "--network=overleaf_default" + "--add-host=mongo:127.0.0.1" + "--health-cmd=echo 'db.stats().ok' | mongosh localhost:27017/test --quiet" + "--health-interval=10s" + "--health-retries=5" + "--health-timeout=10s" + ]; + }; + + overleaf-redis = { + image = with images.redis; imageName + ":" + imageTag; + imageFile = images.redis; + volumes = [ "overleaf_redis-data:/data:rw" ]; + log-driver = "journald"; + extraOptions = [ + "--network-alias=redis" + "--network=overleaf_default" + ]; + }; + + overleaf-sharelatex = { + image = with images.sharelatex; imageName + ":" + imageTag; + imageFile = images.sharelatex; + log-driver = "journald"; + environment = defaultEnv // cfg.environment; + environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile; + volumes = [ "overleaf_data:/var/lib/overleaf:rw" ]; + ports = [ "${toString cfg.port}:80/tcp" ]; + extraOptions = [ + "--network-alias=sharelatex" + "--network=overleaf_default" + ]; + }; + }; + + systemd.services = + let + commonServiceCfg = { + serviceConfig.Restart = mkOverride 90 "always"; + partOf = [ "podman-compose-overleaf-root.target" ]; + wantedBy = [ "podman-compose-overleaf-root.target" ]; + }; + in + { + podman-overleaf-mongo = commonServiceCfg // { + after = [ + "podman-network-overleaf_default.service" + "podman-volume-overleaf_mongo-data.service" + ]; + requires = [ + "podman-network-overleaf_default.service" + "podman-volume-overleaf_mongo-data.service" + ]; + }; + + podman-overleaf-redis = commonServiceCfg // { + after = [ + "podman-network-overleaf_default.service" + "podman-volume-overleaf_redis-data.service" + ]; + requires = [ + "podman-network-overleaf_default.service" + "podman-volume-overleaf_redis-data.service" + ]; + }; + + podman-overleaf-sharelatex = commonServiceCfg // { + after = [ + "podman-network-overleaf_default.service" + "podman-overleaf-mongo.service" + "podman-overleaf-redis.service" + ]; + requires = [ + "podman-network-overleaf_default.service" + "podman-overleaf-mongo.service" + "podman-overleaf-redis.service" + ]; + serviceConfig.ExecStartPre = [ + "${pkgs.bash}/bin/bash -c 'until ${pkgs.podman}/bin/podman healthcheck run overleaf-mongo; do sleep 2; done'" + ]; + }; + + podman-network-overleaf_default = { + path = [ pkgs.podman ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStop = "podman network rm -f overleaf_default"; + }; + script = '' + podman network inspect overleaf_default || podman network create overleaf_default + ''; + partOf = [ "podman-compose-overleaf-root.target" ]; + wantedBy = [ "podman-compose-overleaf-root.target" ]; + }; + + podman-volume-overleaf_redis-data = { + path = [ pkgs.podman ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + podman volume inspect overleaf_redis-data || podman volume create overleaf_redis-data + ''; + partOf = [ "podman-compose-overleaf-root.target" ]; + wantedBy = [ "podman-compose-overleaf-root.target" ]; + }; + + podman-volume-overleaf_mongo-data = { + path = [ pkgs.podman ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + podman volume inspect overleaf_mongo-data || podman volume create overleaf_mongo-data + ''; + partOf = [ "podman-compose-overleaf-root.target" ]; + wantedBy = [ "podman-compose-overleaf-root.target" ]; + }; + }; + + systemd.targets."podman-compose-overleaf-root" = { + unitConfig.Description = "Root target for Overleaf services."; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/modules/nixos/overleaf-oci/mongodb-init-replica-set.js b/modules/nixos/overleaf-oci/mongodb-init-replica-set.js new file mode 100644 index 0000000..30af660 --- /dev/null +++ b/modules/nixos/overleaf-oci/mongodb-init-replica-set.js @@ -0,0 +1,3 @@ +/* eslint-disable no-undef */ + +rs.initiate({ _id: 'overleaf', members: [{ _id: 0, host: 'mongo:27017' }] }) diff --git a/modules/nixos/pki/default.nix b/modules/nixos/pki/default.nix new file mode 100644 index 0000000..9b849f6 --- /dev/null +++ b/modules/nixos/pki/default.nix @@ -0,0 +1,3 @@ +{ + security.pki.certificateFiles = [ ./root_ca.crt ]; +} diff --git a/modules/nixos/pki/root_ca.crt b/modules/nixos/pki/root_ca.crt new file mode 100644 index 0000000..44abf61 --- /dev/null +++ b/modules/nixos/pki/root_ca.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBrzCCAVWgAwIBAgIQDV0M0pLkCXvARpa+ipSx8jAKBggqhkjOPQQDAjA2MRUw +EwYDVQQKEwxzaWQtaW50ZXJuYWwxHTAbBgNVBAMTFHNpZC1pbnRlcm5hbCBSb290 +IENBMB4XDTI2MDQxODIwMzkwMloXDTM2MDQxNTIwMzkwMlowNjEVMBMGA1UEChMM +c2lkLWludGVybmFsMR0wGwYDVQQDExRzaWQtaW50ZXJuYWwgUm9vdCBDQTBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABCH2VmIwKEjdma4UymD7RWuGcaT2algrL5nm +TE0NzP8giezdU9bEP487AvUPPibSYDWxdp4ycbl6qNVTiy29xkmjRTBDMA4GA1Ud +DwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRaiBACRDZk +HZMU9y8YsUF4WPB+5TAKBggqhkjOPQQDAgNIADBFAiAh+b49V2VTnT6nRCRM0Qwq +ruzayrrnmF7pIxi9PVFwBQIhANQsL3ok4gCTRAnT0mUXSyWexzSESZ1lkpLYiyoj +RgLi +-----END CERTIFICATE----- diff --git a/modules/nixos/promtail/default.nix b/modules/nixos/promtail/default.nix deleted file mode 100644 index cdb99de..0000000 --- a/modules/nixos/promtail/default.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ config, constants, ... }: - -{ - services.promtail = { - enable = true; - configuration = { - server = { - http_listen_port = 9080; - grpc_listen_port = 0; - }; - - clients = [ - { - url = "http://${constants.hosts.sid.ip}:3100/loki/api/v1/push"; - } - ]; - - scrape_configs = [ - { - job_name = "journal"; - journal = { - max_age = "12h"; - path = "/var/log/journal"; - - labels = { - job = "systemd-journal"; - host = config.networking.hostName; - }; - }; - - relabel_configs = [ - { - source_labels = [ "__journal__systemd_unit" ]; - target_label = "unit"; - } - ]; - } - ]; - }; - }; - - users.users.promtail.extraGroups = [ "systemd-journal" ]; -} diff --git a/modules/nixos/tailscale/default.nix b/modules/nixos/tailscale/default.nix index f42bb85..884847a 100644 --- a/modules/nixos/tailscale/default.nix +++ b/modules/nixos/tailscale/default.nix @@ -11,7 +11,7 @@ loginServer = "https://hs.sid.ovh"; authKeyFile = config.sops.secrets."tailscale/personal-key".path; enableSSH = true; - acceptDNS = true; + acceptDNS = false; # use coredns }; }; };