diff --git a/constants.nix b/constants.nix index 5dfa26e..aeb5aea 100644 --- a/constants.nix +++ b/constants.nix @@ -25,23 +25,26 @@ 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 = "netdata." + intranet; + fqdn = "mon." + domain; 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; @@ -51,12 +54,8 @@ rec { port = 1200; }; vaultwarden = { - fqdn = "pw." + intranet; + fqdn = "pw." + domain; port = 8222; }; - webdav = { - fqdn = "dav." + intranet; - port = 8080; - }; }; } diff --git a/flake.lock b/flake.lock index da7918e..b0a6409 100644 --- a/flake.lock +++ b/flake.lock @@ -5199,11 +5199,11 @@ "stylix": "stylix_6" }, "locked": { - "lastModified": 1778016348, - "narHash": "sha256-C8PtC95r1KJync8qDEroIont1VT8tiwsjonYjwGLhbY=", + "lastModified": 1779222589, + "narHash": "sha256-pFlaPXus8e+mY9C7/xQhBwux6tPk5P30K2uaN2Qluh0=", "ref": "release-25.11", - "rev": "8ad8b1f633f6c3875032a0ead0e87255dff4ab3c", - "revCount": 57, + "rev": "1ab817090ff5989578caefd8786e9450b37e3da5", + "revCount": 96, "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 0aa47f7..2b66560 100644 --- a/hosts/rx4/secrets/secrets.yaml +++ b/hosts/rx4/secrets/secrets.yaml @@ -13,12 +13,17 @@ 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 @@ -39,7 +44,7 @@ sops: NE5yK3ZaOG5PdXNSUnlIUmFSSmRFancKk57hCmo79HvI3hzzgQvgOK7oK5/dcQR8 f3R4OGF5+212VXEHR/hAEbKzV7CY4y6HhFyrGZ9bUKm1RrxtnVqUyA== -----END AGE ENCRYPTED FILE----- - 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] + lastmodified: "2026-05-25T18:14:59Z" + mac: ENC[AES256_GCM,data:eh/jcKrqyCTh+2n4phHQ2LKF71DaCDwrrfXms6HaD0ER4xVOkYERTe7IN4cX//qjY/91wSzAzwLg3yphWK4k920tiYTBog9LcWUz6l6X5lpmKHQp+vdoQH41WrA1ZgOcXzSfmZoblcD1qoJNCaHGt5N8hjXRcUc3lEqcPrdoC7A=,iv:8kBd9Daai3wJgzxONX4eIkeZLMzJO2DX439sBv/pER4=,tag:l8Q3gzMHoSTCdOqwzaKgCA==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1 diff --git a/hosts/rx4/services/default.nix b/hosts/rx4/services/default.nix index df12843..8694146 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 new file mode 100644 index 0000000..25149dc --- /dev/null +++ b/hosts/rx4/services/librechat-oci.nix @@ -0,0 +1,71 @@ +{ + 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 new file mode 100644 index 0000000..327012a --- /dev/null +++ b/hosts/rx4/services/librechat.yaml @@ -0,0 +1,53 @@ +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 30d720d..956f612 100644 --- a/hosts/rx4/services/netdata.nix +++ b/hosts/rx4/services/netdata.nix @@ -1,12 +1,14 @@ { config, constants, + pkgs, ... }: { services.netdata = { enable = true; + package = pkgs.netdata.override { withCloudUi = false; }; config.global = { "debug log" = "syslog"; "access log" = "syslog"; @@ -17,6 +19,10 @@ }; }; + 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 c4c24af..cae8e31 100644 --- a/hosts/rx4/services/nginx.nix +++ b/hosts/rx4/services/nginx.nix @@ -7,6 +7,8 @@ let cfg = config.services.nginx; + + inherit (constants) domain; in { imports = [ @@ -34,4 +36,21 @@ 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 5c43197..f22297d 100644 --- a/hosts/rx4/services/open-webui-oci.nix +++ b/hosts/rx4/services/open-webui-oci.nix @@ -2,12 +2,19 @@ inputs, constants, config, + lib, pkgs, ... }: +let + inherit (lib) getExe; +in { - imports = [ inputs.synix.nixosModules.open-webui-oci ]; + imports = [ + inputs.synix.nixosModules.open-webui-oci + inputs.synix.nixosModules.mcpo + ]; services.open-webui-oci = { enable = true; @@ -21,6 +28,27 @@ }; }; + 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 deleted file mode 100644 index 575012f..0000000 --- a/hosts/rx4/services/overleaf-oci.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ 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 deleted file mode 100644 index 64037fd..0000000 --- a/hosts/rx4/services/print-server.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ - 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 new file mode 100644 index 0000000..2696005 --- /dev/null +++ b/hosts/rx4/services/samba.nix @@ -0,0 +1,27 @@ +{ 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 6f00505..d9f8092 100644 --- a/hosts/rx4/services/vaultwarden.nix +++ b/hosts/rx4/services/vaultwarden.nix @@ -6,6 +6,7 @@ let inherit (constants) domain; + inherit (constants.hosts.rx4) ip; inherit (constants.services.vaultwarden) fqdn port; in { @@ -21,21 +22,52 @@ 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.hosts.sid.ip; - SMTP_PORT = 587; - SMTP_SECURITY = "starttls"; + SMTP_HOST = constants.services.mailserver.fqdn; + SMTP_PORT = 465; + SMTP_SECURITY = "force_tls"; SMTP_USERNAME = "vaultwarden@${domain}"; - ROCKET_ADDRESS = "0.0.0.0"; + ROCKET_ADDRESS = "127.0.0.1"; 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 deleted file mode 100644 index 46d01a9..0000000 --- a/hosts/rx4/services/webdav.nix +++ /dev/null @@ -1,86 +0,0 @@ -{ 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 8fb0e4a..f94edbf 100644 --- a/hosts/sid/secrets/secrets.yaml +++ b/hosts/sid/secrets/secrets.yaml @@ -35,6 +35,7 @@ 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 @@ -55,7 +56,7 @@ sops: RzhnczA0S1pxcXZncGpWVHNYQW96L28K+ytH3PPyg4+wibpAQhp02RiSfZ83EDRB UJ8UV1d+51D0e2A1sI95r2AzDj4jfwUnI+LYDPC/qEpsu5LFLGVyeg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-02T17:10:22Z" - mac: ENC[AES256_GCM,data:f4KQ26/zvg2nLLeW5qVeI8uH2GmPpJUKohNu68nEiIjP5AT53zjBaGoLOTGl9+oVRomSOGZtLGkJGaExB6tLMon5HN6xkQbugqvq08UkZ7FnR1Sa8/OtTr/+eexPNzF8VSdZE2TZCboUSQODV8+0Cy5T918g5kedxnT62SyY4As=,iv:P4TnpJvHwnZPl7kRNjv9d1WLZP9J0sg6R3KbdDMJqyc=,tag:ylYOcg6825jT29lWUaFRYA==,type:str] + lastmodified: "2026-05-22T19:19:21Z" + mac: ENC[AES256_GCM,data:hOtmWizEaIcybM14UEDsXw4GNQZob5SoFn49bWeccxA3dkGlYl67kVkDJGg0cQIO1qr/vGcZ8h/OmnOxU3geP0DaflG0h1/40lDQ3+E6BTb6HP2JmhgEmlRBRBdv87cRDHnDytBzcWARTvff3SsP2J2pLpLBTDiihlaZaiQYtgU=,iv:TvFpvcTydXO3fbh5x9ZXIOtMChlE7WXl2Xx2a9ujh00=,tag:XHvsZh6r9fzbbYFWWQyI5g==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1 diff --git a/hosts/sid/services/coredns.nix b/hosts/sid/services/coredns.nix deleted file mode 100644 index c7af795..0000000 --- a/hosts/sid/services/coredns.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ 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 c1079d8..ee63f99 100644 --- a/hosts/sid/services/default.nix +++ b/hosts/sid/services/default.nix @@ -9,8 +9,9 @@ inputs.synix.nixosModules.openssh outputs.nixosModules.tailscale + # outputs.nixosModules.loki + # outputs.nixosModules.promtail - ./coredns.nix ./headscale.nix ./mailserver.nix ./matrix-synapse.nix @@ -18,6 +19,5 @@ ./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 6c7148f..0d4a03f 100644 --- a/hosts/sid/services/headscale.nix +++ b/hosts/sid/services/headscale.nix @@ -1,5 +1,6 @@ { inputs, + constants, ... }: @@ -24,5 +25,12 @@ 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 f3af274..c70433e 100644 --- a/hosts/sid/services/mailserver.nix +++ b/hosts/sid/services/mailserver.nix @@ -1,15 +1,21 @@ -{ inputs, config, ... }: +{ inputs, constants, ... }: +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 = [ "postmaster" ]; + aliases = [ + "admin" + "postmaster" + ]; }; vaultwarden = { }; }; diff --git a/hosts/sid/services/netdata.nix b/hosts/sid/services/netdata.nix index 005f9e1..6733c2a 100644 --- a/hosts/sid/services/netdata.nix +++ b/hosts/sid/services/netdata.nix @@ -1,18 +1,37 @@ { 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 = true; - }; + package = pkgs.netdata.override { withCloudUi = false; }; config.global = { "debug log" = "syslog"; "access log" = "syslog"; @@ -36,6 +55,47 @@ 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; @@ -44,6 +104,12 @@ in restartUnits = [ "netdata.service" ]; in { + secrets.hetzner-api-key = { + inherit mode; + owner = "acme"; + group = "acme"; + }; + secrets."netdata/stream/rx4/uuid" = { inherit owner @@ -65,6 +131,7 @@ 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 1c2f432..0844781 100644 --- a/hosts/sid/services/nginx.nix +++ b/hosts/sid/services/nginx.nix @@ -56,15 +56,6 @@ 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; @@ -77,33 +68,11 @@ 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 deleted file mode 100644 index d3abb11..0000000 --- a/hosts/sid/services/step-ca.nix +++ /dev/null @@ -1,108 +0,0 @@ -{ - 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 0415b9f..71660e5 100644 --- a/modules/nixos/common/default.nix +++ b/modules/nixos/common/default.nix @@ -5,10 +5,6 @@ ./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 1028fdf..d3511ee 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; - overleaf-oci = import ./overleaf-oci; - pki = import ./pki; + promtail = import ./promtail; 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 new file mode 100644 index 0000000..2009e52 --- /dev/null +++ b/modules/nixos/loki/dashboards/logs.json @@ -0,0 +1,75 @@ +{ + "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 new file mode 100644 index 0000000..e5fdd14 --- /dev/null +++ b/modules/nixos/loki/default.nix @@ -0,0 +1,115 @@ +{ + 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 deleted file mode 100644 index 6be248b..0000000 --- a/modules/nixos/overleaf-oci/default.nix +++ /dev/null @@ -1,257 +0,0 @@ -{ - 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 deleted file mode 100644 index 30af660..0000000 --- a/modules/nixos/overleaf-oci/mongodb-init-replica-set.js +++ /dev/null @@ -1,3 +0,0 @@ -/* 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 deleted file mode 100644 index 9b849f6..0000000 --- a/modules/nixos/pki/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - security.pki.certificateFiles = [ ./root_ca.crt ]; -} diff --git a/modules/nixos/pki/root_ca.crt b/modules/nixos/pki/root_ca.crt deleted file mode 100644 index 44abf61..0000000 --- a/modules/nixos/pki/root_ca.crt +++ /dev/null @@ -1,12 +0,0 @@ ------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 new file mode 100644 index 0000000..cdb99de --- /dev/null +++ b/modules/nixos/promtail/default.nix @@ -0,0 +1,43 @@ +{ 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 884847a..f42bb85 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 = false; # use coredns + acceptDNS = true; }; }; };