4HN5LZRSOAODRIM57WBB35C66VO7BR4PGFINLUMTGNHULEK43CEQC {config.flake.modules.nixos.uptime-kuma ={ config, lib, ... }:letinherit (config.networking) domain;inherit (lib) enabled merge;fqdn = "uptime.${domain}";port = "3001"; # string for uptime-kumain{imports = [ ./nginx.nix ];services.uptime-kuma = enabled {settings = {inherit port;HOST = "127.0.0.1";};};services.nginx.virtualHosts.${fqdn} = merge config.services.nginx.sslTemplate {serverAliases = [ "status.${domain}" ];locations."/" = {proxyPass = "http://127.0.0.1:${toString port}";proxyWebsockets = true;extraConfig = ''proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;'';};};};}
{ self, config, lib, ... }: letinherit (lib) enabled filterAttrs flatten mapAttrsToList;in {services.grafana.provision.datasources.settings = {datasources = [{name = "Prometheus";type = "prometheus";url = "http://[::1]:${toString config.services.prometheus.port}";orgId = 1;}];deleteDatasources = [{name = "Prometheus";orgId = 1;}];};services.prometheus = enabled {listenAddress = "[::]";retentionTime = "1w";scrapeConfigs = letconfigToScrapeConfig = hostName: { config, ... }: lethostConfig = config;in hostConfig.services.prometheus.exporters|> filterAttrs (exporterName: exporterConfig:exporterName != "minio" &&exporterName != "unifi-poller" &&exporterName != "tor" &&exporterConfig.enable or false)|> mapAttrsToList (exporterName: exporterConfig: {job_name = "${exporterName}-${hostName}";static_configs = [{targets = [ "${hostName}:${toString exporterConfig.port}" ];}];});in self.nixosConfigurations|> mapAttrsToList configToScrapeConfig|> flatten;};}
{config.flake.modules.nixos.personal-site ={self,config,lib,...}:letinherit (config.networking) domain;inherit (lib) merge;fqdn = domain;root = "/var/www/site";in{imports = [ (self + /modules/nginx.nix) ];services.nginx = {enable = true;virtualHosts."www.${fqdn}" = merge config.services.nginx.sslTemplate {locations."/".return = "301 https://${fqdn}$request_uri";};virtualHosts."nerd.${fqdn}" = merge config.services.nginx.sslTemplate {root = "${root}/nerd";locations."/" = {tryFiles = "$uri $uri.html $uri/index.html =404";extraConfig = ''proxy_hide_header Content-Security-Policy;add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain} kit.fontawesome.com https://kit.fontawesome.com; script-src-elem 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain} kit.fontawesome.com https://kit.fontawesome.com; img-src 'self' data: https: ghchart.rshah.org;" always;add_header X-Frame-Options DENY always;add_header X-Content-Type-Options nosniff always;add_header X-XSS-Protection "1; mode=block" always;add_header Permissions-Policy "camera=(), geolocation=(), payment=(), usb=()" always;add_header Referrer-Policy no-referrer always;'';};locations."~ ^/assets/(fonts|icons|images)/".extraConfig = /* nginx */ ''expires max;${config.services.nginx.headers}add_header Cache-Control $cache_header always;'';extraConfig = /* nginx */ ''error_page 404 /404.html;${config.services.nginx.goatCounterTemplate}'';locations."/404".extraConfig = /* nginx */ ''internal;'';};virtualHosts._ = merge config.services.nginx.sslTemplate {locations."/".return = "301 https://${fqdn}/404";};virtualHosts.${fqdn} = merge config.services.nginx.sslTemplate {inherit root;locations."/" = {tryFiles = "$uri $uri.html $uri/index.html =404";extraConfig = ''proxy_hide_header Content-Security-Policy;add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain} kit.fontawesome.com https://kit.fontawesome.com; script-src-elem 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain} kit.fontawesome.com https://kit.fontawesome.com; img-src 'self' data: https: ghchart.rshah.org;" always;add_header X-Frame-Options DENY always;add_header X-Content-Type-Options nosniff always;add_header X-XSS-Protection "1; mode=block" always;add_header Permissions-Policy "camera=(), geolocation=(), payment=(), usb=()" always;add_header Referrer-Policy no-referrer always;'';};locations."~ ^/assets/(fonts|icons|images)/".extraConfig = /* nginx */ ''expires max;${config.services.nginx.headers}add_header Cache-Control $cache_header always;'';extraConfig = /* nginx */ ''error_page 404 /404.html;${config.services.nginx.goatCounterTemplate}'';locations."/404".extraConfig = /* nginx */ ''internal;'';};};};}
{config.flake.modules.nixos.nginx ={self,config,lib,...}:letinherit (config.networking) domain;inherit (lib) enabled mkConst;in{imports = [ (self + /modules/acme) ];options.services.nginx.sslTemplate = mkConst {forceSSL = true;quic = true;useACMEHost = domain;};options.services.nginx.goatCounterTemplate = mkConst /* nginx */ ''proxy_set_header Accept-Encoding "";sub_filter "</head>" '<script data-goatcounter="https://analytics.${domain}/count" async src="https://analytics.${domain}/count.js"></script></head>';sub_filter_last_modified on;sub_filter_once on;'';options.services.nginx.headers = mkConst /* nginx */ ''proxy_hide_header Access-Control-Allow-Origin;add_header Access-Control-Allow-Origin $allow_origin always;${config.services.nginx.headersNoAccessControlOrigin}'';options.services.nginx.headersNoAccessControlOrigin = mkConst /* nginx */ ''proxy_hide_header Access-Control-Allow-Methods;add_header Access-Control-Allow-Methods $allow_methods always;proxy_hide_header Strict-Transport-Security;add_header Strict-Transport-Security $hsts_header always;proxy_hide_header Content-Security-Policy;add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain}; object-src 'self' ${domain} *.${domain}; img-src 'self' data: https:; base-uri 'self'; frame-ancestors 'self';" always;proxy_hide_header Referrer-Policy;add_header Referrer-Policy no-referrer always;proxy_hide_header X-Frame-Options;add_header X-Frame-Options DENY always;proxy_hide_header X-Content-Type-Options;add_header X-Content-Type-Options nosniff always;proxy_hide_header X-XSS-Protection;add_header X-XSS-Protection "1; mode=block" always;proxy_hide_header Permissions-Policy;add_header Permissions-Policy "camera=(), geolocation=(), payment=(), usb=()" always;'';config.networking.firewall = {allowedTCPPorts = [44380];allowedUDPPorts = [ 443 ];};config.services.prometheus.exporters.nginx = enabled {listenAddress = "[::]";};config.security.acme.users = [ "nginx" ];config.services.nginx = enabled {statusPage = true;recommendedBrotliSettings = true;recommendedGzipSettings = true;recommendedOptimisation = true;recommendedProxySettings = true;recommendedTlsSettings = true;commonHttpConfig = /* nginx */ ''map $scheme $hsts_header {https "max-age=31536000; includeSubdomains; preload";}# cache only successful responsesmap $status $cache_header {200 "public";302 "public";default "no-cache";}map $http_origin $allow_origin {~^https://(?:.+\.)?${domain}$ $http_origin;~^https://dr-radka\.pl$ $http_origin;~^https://awesome-technologies\.github\.io$ $http_origin;}map $http_origin $allow_methods {~^https://(?:.+\.)?${domain}$ "CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE";~^https://dr-radka\.pl$ "CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE";~^https://awesome-technologies\.github\.io$ "CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE";}${config.services.nginx.headers}proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";'';};};}
{ self, config, lib, ... }: letinherit (config.networking) domain;inherit (lib) enabled;fqdn = "matrix.${domain}";port = 8008;in {imports = [(self + /modules/nginx.nix)] ++ (lib.collectNix ./. |> lib.remove ./default.nix);age.secrets.matrixSigningKey = {rekeyFile = self + /secrets/plum-matrix-signing-key.age;owner = "matrix-synapse";group = "matrix-synapse";};age.secrets.matrixRegistrationSecret = {rekeyFile = self + /secrets/plum-matrix-registration-secret.age;owner = "matrix-synapse";group = "matrix-synapse";};systemd.services.matrix-backup = {description = "Backup Matrix data and database";after = [ "matrix-synapse.service" ];script = ''mkdir -p /var/backup/matrixcp -r /var/lib/matrix-synapse /var/backup/matrix/$(date +%Y%m%d_%H%M%S)# keep only last 7 backupsls -1t /var/backup/matrix/ | tail -n +8 | xargs -r rm -rf'';serviceConfig.Type = "oneshot";serviceConfig.User = "matrix-synapse";};systemd.timers.matrix-backup = {description = "Run Matrix backup daily";wantedBy = [ "timers.target" ];timerConfig.OnCalendar = "daily";timerConfig.Persistent = true;};systemd.services.matrix-synapse.serviceConfig = {# sandboxingPrivateTmp = true;ProtectSystem = "strict";ProtectHome = true;# fs restrictionsReadWritePaths = [ "/var/lib/matrix-synapse" ];# network restrictionsRestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];# miscNoNewPrivileges = true;RestrictSUIDSGID = true;};services.matrix-synapse = enabled {withJemalloc = true;configureRedisLocally = true;settings = {server_name = domain;listeners = [{port = port;bind_addresses = [ "::1" ];type = "http";tls = false;x_forwarded = true; # behind reverse proxyresources = [{names = [ "client" "federation" "media" ];compress = false;}];}];database.name = "sqlite3";database.args.database = "/var/lib/matrix-synapse/homeserver.db";log_config = "/var/lib/matrix-synapse/log.yaml";log.root.level = "WARNING";enable_registration = true;registration_requires_token = true;allow_public_rooms_without_auth = true;allow_public_rooms_over_federation = true;report_stats = false;delete_stale_devices_after = "30d";redis.enabled = true;max_upload_size = "512M";media_store_path = "/var/lib/matrix-synapse/media_store";url_preview_enabled = true;dynamic_thumbnails = true;signing_key_path = config.age.secrets.matrixSigningKey.path;registration_shared_secret = config.age.secrets.matrixRegistrationSecret.path;trusted_key_servers = [];extras = [ "url-preview" "user-search" ];};};services.nginx.virtualHosts.${fqdn} = lib.merge config.services.nginx.sslTemplate {extraConfig = ''${config.services.nginx.goatCounterTemplate}'';locations."/_matrix".proxyPass = "http://[::1]:${toString port}";locations."/_synapse/client".proxyPass = "http://[::1]:${toString port}";locations."/_synapse/admin".proxyPass = "http://[::1]:${toString port}";};services.nginx.virtualHosts.${domain} = lib.merge config.services.nginx.sslTemplate {locations."/.well-known/matrix/client".extraConfig = ''return 200 '{"m.homeserver": {"base_url": "https://${fqdn}"}}';'';locations."/.well-known/matrix/server".extraConfig = ''return 200 '{"m.server": "${fqdn}:443"}';'';};}
{ config, lib, pkgs, ... }: letinherit (lib) mkIf;helium-browser = letversion = "0.6.3.1";# I don't care about aarch64 because I have no aarch64 machines.# Keep that in mind if you're copying this.arch = if config.isLinux then {arch = "x86_64";hash = "sha256:37b2692cb39db2762ecd8ade37589a1c8f7dd8c4764ae5d39971df6ba7ddd545";} else null;inif arch == null then null elsepkgs.appimageTools.wrapType2 {pname = "helium-browser";inherit version;src = pkgs.fetchurl {url = "https://github.com/imputnet/helium-linux/releases/download/${version}/helium-${version}-${arch.arch}.AppImage";inherit (arch) hash;};};in {home-manager.sharedModules = mkIf (config.isDesktopNotWsl && helium-browser != null) [{home.packages = [ helium-browser ];xdg.desktopEntries.helium-browser = {name = "Helium Browser";icon = "helium-browser";exec = "helium-browser";terminal = false;};}];}
{ pkgs, lib, config, ... }: letinherit (lib) mkIf;in {environment.systemPackages = mkIf config.isDesktop [pkgs.cabal-installpkgs.haskell.compiler.ghc912pkgs.haskellPackages.hlintpkgs.stack];}
{ self, config, lib, ... }: letinherit (config.networking) domain;inherit (lib) enabled merge;fqdn = "metrics.${domain}";port = 8000;in {imports = [(self + /modules/nginx.nix)] ++ (lib.collectNix ./. |> lib.remove ./default.nix);age.secrets.grafanaPassword = {rekeyFile = self + /secrets/plum-grafana-password.age;owner = "grafana";};systemd.services.grafana = {after = [ "network.target" ];requires = [ "network.target" ];};services.grafana = enabled {provision = enabled;settings = {analytics.reporting_enabled = false;database.type = "sqlite3";server.domain = fqdn;server.http_addr = "::1";server.http_port = port;users.default_theme = "system";};settings.security = {admin_email = "metrics@${domain}";admin_password = "$__file{${config.age.secrets.grafanaPassword.path}}";admin_user = "admin";disable_initial_admin_creation = true; # after initial creationcookie_secure = true;disable_gravatar = true;};};services.nginx.virtualHosts.${fqdn} = merge config.services.nginx.sslTemplate {extraConfig = ''${config.services.nginx.goatCounterTemplate}'';locations."/" = {extraConfig = /* nginx */ ''# grafana sets `nosniff` without correct content type so unset the headerproxy_hide_header X-Content-Type-Options;'';proxyPass = "http://[::1]:${toString port}";proxyWebsockets = true;};};}
{config.flake.modules.nixos.goatcounter ={ config, ... }:letinherit (config.network) domain;fqdn = "analytics.${domain}";port = 8007;in{config = {services.goatcounter = {inherit port;enable = true;proxy = true;address = "127.0.0.1";};services.nginx.virtualHosts.${fqdn} = lib.merge config.services.nginx.sslTemplate {locations."/" = {proxyPass = "http://127.0.0.1:${toString port}";proxyWebsockets = true;extraConfig = ''proxy_hide_header X-Content-Type-Options;'';};};};};}
{ pkgs, lib, config, ... }: letinherit (lib) enabled mkIf mapAttrsToList;in mkIf config.isDesktopNotWsl {home-manager.sharedModules = [{programs.ghostty = enabled {clearDefaultKeybinds = true;installBatSyntax = true;settings = with config.theme; {font-size = font.size.term;font-family = font.mono.name;font-feature = "+calt, +liga, +dlig";theme = if config.theme.color_scheme == "pywal" then "custom" else config.theme.ghostty;window-padding-x = padding.small;window-padding-y = padding.small;window-decoration = false;scrollback-limit = 100 * 1024 * 1024; # 100 MiBmouse-hide-while-typing = true;confirm-close-surface = false;quit-after-last-window-closed = true;keybind = mapAttrsToList (name: value: "ctrl+shift+${name}=${value}") {c = "copy_to_clipboard";v = "paste_from_clipboard";i = "inspector:toggle";plus = "increase_font_size:1";minus = "decrease_font_size:1";equal = "reset_font_size";};};themes = with config.theme.withHash; {custom = {background = base00;cursor-color = base05;foreground = base05;selection-background = base02;selection-foreground = base00;palette = mapAttrsToList (name: value: "${name}=${value}") {"0" = base00;"1" = base01;"2" = base02;"3" = base03;"4" = base04;"5" = base05;"6" = base06;"7" = base07;"8" = base08;"9" = base09;"10" = base0A;"11" = base0B;"12" = base0C;"13" = base0D;"14" = base0E;"15" = base0F;};};};};# Desktop entry for Zellij in Fuzzel.xdg.desktopEntries.zellij-ghostty = {name = "Zellij Ghostty";icon = "ghostty";exec = "ghostty -e ${pkgs.zellij}/bin/zellij";terminal = false;};}];}
{ pkgs, self, config, lib, ... }: letinherit (config.networking) domain;inherit (lib) enabled mkForce;fqdn = "git.${domain}";port = 8001;in {imports = [./nginx.nix];age.secrets.forgejoAdminPassword = {rekeyFile = self + /secrets/plum-forgejo-password.age;owner = "forgejo";};# combine AcceptEnv settings for SSH and Git protocolservices.openssh.settings.AcceptEnv = mkForce [ "SHELLS" "COLORTERM" "GIT_PROTOCOL" ];# backup configuration for sqlite database and datasystemd.services.forgejo-backup = {description = "Backup Forgejo data and database";after = [ "forgejo.service" ];script = ''mkdir -p /var/backup/forgejocp -r /var/lib/forgejo /var/backup/forgejo/$(date +%Y%m%d_%H%M%S)# keep only last 7 backupsls -1t /var/backup/forgejo/ | tail -n +8 | xargs -r rm -rf'';serviceConfig = {Type = "oneshot";User = "forgejo";};};systemd.timers.forgejo-backup = {description = "Run Forgejo backup daily";wantedBy = [ "timers.target" ];timerConfig = {OnCalendar = "daily";Persistent = true;};};services.forgejo = enabled {package = pkgs.forgejo; # The service version is ~11 so better to specify and get the latest.lfs = enabled;user = "forgejo";database = {type = "sqlite3";};settings = letdescription = "PlumJam's Git Forge";in {default.APP_NAME = description;attachment.ALLOWED_TYPES = "*/*";cache.ENABLED = true;# archive cleanup cron job"cron.archive_cleanup" = letinterval = "4h";in {SCHEDULE = "@every ${interval}";OLDER_THAN = interval;};other = {SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;SHOW_FOOTER_VERSION = false;};packages.ENABLED = true;repository = {DEFAULT_BRANCH = "master";DEFAULT_MERGE_STYLE = "rebase-merge";DEFAULT_REPO_UNITS = "repo.code, repo.issues, repo.pulls";DEFAULT_PUSH_CREATE_PRIVATE = false;ENABLE_PUSH_CREATE_ORG = true;ENABLE_PUSH_CREATE_USER = true;DISABLE_STARS = true;};"repository.upload" = {FILE_MAX_SIZE = 100;MAX_FILES = 10;};server = {DOMAIN = domain;ROOT_URL = "https://${fqdn}/";LANDING_PAGE = "/explore";HTTP_ADDR = "::1";HTTP_PORT = port;SSH_DOMAIN = fqdn;SSH_PORT = 22;START_SSH_SERVER = false;DISABLE_ROUTER_LOG = true;};service.DISABLE_REGISTRATION = true;session = {COOKIE_SECURE = true;SAME_SITE = "strict";};"ui.meta" = {AUTHOR = description;DESCRIPTION = description;};};};services.nginx.virtualHosts.${fqdn} = lib.merge config.services.nginx.sslTemplate {extraConfig = ''${config.services.nginx.goatCounterTemplate}'';locations."/".proxyPass = "http://[::1]:${toString port}";};}
{config.flake.modules.nixos.forgejo-action-runner ={self,config,lib,pkgs,inputs,...}:letinherit (lib)mkIfmkOptiontypes;in{options.ci-runner = {enable = lib.mkEnableOption "forgejo CI runner";tokenFile = mkOption {type = types.path;description = "Path to the runner token file";};url = mkOption {type = types.str;default = "https://git.plumj.am/";description = "Forgejo instance URL";};labels = mkOption {type = types.listOf types.str;default = [ "self-hosted:host" ];description = "Runner labels";};extraHostPackages = mkOption {type = types.listOf types.package;default = [ ];description = "Extra packages to add to the runner";};withDocker = mkOption {type = types.bool;default = false;description = "Include docker and docker-compose";};};config = mkIf config.ci-runner.enable {age.secrets.forgejoRunnerToken.rekeyFile = config.ci-runner.tokenFile;users.groups.gitea-runner = { };users.users.gitea-runner = {description = "gitea-runner";isSystemUser = true;group = "gitea-runner";};services.gitea-actions-runner = {package = pkgs.forgejo-runner;instances.${config.networking.hostName} = {enable = true;name = config.networking.hostName;tokenFile = config.age.secrets.forgejoRunnerToken.path;url = config.ci-runner.url;labels = config.ci-runner.labels;settings.cache.enabled = false;hostPackages = [(inputs.fenix.packages.${pkgs.stdenv.hostPlatform.system}.complete.withComponents ["cargo""clippy""miri""rustc""rust-analyzer""rustfmt""rust-std""rust-src"])inputs.claude-code.packages.${pkgs.stdenv.hostPlatform.system}.defaultpkgs.bashpkgs.curlpkgs.forgejo-clipkgs.gccpkgs.gitpkgs.gnutarpkgs.gzippkgs.justpkgs.jqpkgs.nixpkgs.nodejspkgs.nushellpkgs.opencodepkgs.opensslpkgs.pkg-configpkgs.ripgreppkgs.sqlx-clipkgs.whichpkgs.xz]++ lib.optionals config.ci-runner.withDocker [pkgs.dockerpkgs.docker-compose]++ config.ci-runner.extraHostPackages;};};};};}
{ lib, config, ... }: letinherit (lib) disabled mkIf;in mkIf config.isDesktopNotWsl {home-manager.sharedModules = [{programs.foot = disabled {settings = {main = with config.theme.font; {font = "${mono.name}:size=${toString size.term}";dpi-aware = "yes";};colors = with config.theme.colors; {background = base00;foreground = base05;urls = base0D;regular0 = base00;regular1 = base08;regular2 = base0B;regular3 = base0A;regular4 = base0D;regular5 = base0E;regular6 = base0C;regular7 = base05;};};};}];}
{config.flake.modules.nixos.dr-radka-site ={self,config,lib,pkgs,...}:letinherit (config.networking) domain;inherit (lib) enabled merge;app_port = 3000;app_user = "dr-radka";app_group = "dr-radka";app_dir = "/var/lib/dr-radka";build_dir = "${app_dir}/build";in{imports = [ (self + /modules/nginx.nix) ];users.users.${app_user} = {isSystemUser = true;group = app_group;home = app_dir;createHome = true;};users.groups.${app_group} = { };systemd.services.dr-radka = {description = "Dr. Radka SvelteKit Application";after = [ "network.target" ];wantedBy = [ "multi-user.target" ];serviceConfig = {Type = "simple";User = app_user;Group = app_group;WorkingDirectory = build_dir;ExecStart = "${pkgs.bun}/bin/bun run ./index.js";Restart = "always";RestartSec = 5;EnvironmentFile = config.age.secrets.dr-radka-environment.path;# hardeningNoNewPrivileges = true;ProtectSystem = "strict";ProtectHome = true;ReadWritePaths = [ app_dir ];PrivateTmp = true;ProtectKernelTunables = true;ProtectKernelModules = true;ProtectControlGroups = true;};environment = {NODE_ENV = "production";PORT = toString app_port;HOST = "127.0.0.1";ORIGIN = "https://${domain}";};path = [ pkgs.bun ];};services.nginx = {enable = true;# Redirect www.dr-radka.pl to dr-radka.plvirtualHosts."www.${domain}" = merge config.services.nginx.sslTemplate {locations."/".return = "301 https://${domain}$request_uri";};virtualHosts.${domain} = merge config.services.nginx.sslTemplate {extraConfig = ''${config.services.nginx.goatCounterTemplate}'';locations."/" = {proxyPass = "http://127.0.0.1:${toString app_port}";proxyWebsockets = true;extraConfig = ''proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_cache_bypass $http_upgrade;# override csp for built app requirements and maintain security headersproxy_hide_header Content-Security-Policy;add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain} cdn.jsdelivr.net unpkg.com *.posthog.com *.sanity.io *.googletagmanager.com *.google-analytics.com analytics.plumj.am; object-src 'self' ${domain} *.${domain}; base-uri 'self'; frame-ancestors 'self' dr-radka.sanity.studio *.sanity.io; form-action 'self' ${domain} *.${domain}; font-src 'self' ${domain} *.${domain} cdn.jsdelivr.net; connect-src 'self' ${domain} *.${domain} unpkg.com *.posthog.com *.sanity.io *.googletagmanager.com *.google-analytics.com analytics.plumj.am; img-src 'self' ${domain} *.${domain} unpkg.com *.tile.openstreetmap.org *.sanity.io cdn.sanity.io www.googletagmanager.com data:;" always;# need to fix because I can't access nested routes in sanity presentation modeadd_header X-Frame-Options DENY always;add_header X-Content-Type-Options nosniff always;add_header X-XSS-Protection "1; mode=block" always;add_header Permissions-Policy "camera=(), geolocation=(), payment=(), usb=()" always;add_header Referrer-Policy no-referrer always;'';};};};environment.systemPackages = [pkgs.nodejs_22pkgs.bun];};}
{ self, config, lib, pkgs, ... }: letinherit (config.networking) domain;inherit (lib) merge;inherit (lib.strings) toJSON;fqdn = "chat.${domain}";root = pkgs.cinny;cinnyConfig = {allowCustomHomeservers = false;homeserverList = [ domain ];defaultHomeserver = 0;hashRouter = {enabled = false;basename = "/";};featuredCommunities = {openAsDefault = false;servers = [domain"matrix.org"];spaces = [ ];rooms = [ ];};};in {imports = [ (self + /modules/nginx.nix) ];services.nginx.virtualHosts.${fqdn} = merge config.services.nginx.sslTemplate {inherit root;locations."= /config.json".extraConfig = /* nginx */ ''default_type application/json;return 200 '${toJSON cinnyConfig}';'';locations."/".extraConfig = /* nginx */ ''proxy_hide_header Content-Security-Policy;add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval' ${domain} *.${domain}; object-src 'self' ${domain} *.${domain}; img-src 'self' data: https: blob:; base-uri 'self'; frame-ancestors 'self';" always;add_header X-Frame-Options DENY always;add_header X-Content-Type-Options nosniff always;add_header X-XSS-Protection "1; mode=block" always;add_header Permissions-Policy "camera=(), geolocation=(), payment=(), usb=()" always;add_header Referrer-Policy no-referrer always;'';extraConfig = /* nginx */ ''rewrite ^/config.json$ /config.json break;rewrite ^/manifest.json$ /manifest.json break;rewrite ^/sw.js$ /sw.js break;rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break;rewrite ^/public/(.*)$ /public/$1 break;rewrite ^/assets/(.*)$ /assets/$1 break;rewrite ^(.+)$ /index.html break;'';};}
{ self, config, lib, pkgs, ... }: letinherit (lib) enabled merge mkIf mkOption types;inherit (config.networking) domain;in {imports = [(self + /modules/nginx.nix)];options.cache = {enable = lib.mkEnableOption "nix-serve cache server";fqdn = lib.mkOption {type = types.str;example = "cache1.example.com";description = "Fully qualified domain name for the cache";};port = lib.mkOption {type = types.port;default = 8006;description = "Port for nix-serve to listen on";};secretKeyFile = lib.mkOption {type = types.path;example = "/run/agenix/nixServeKey";description = "Path to the secret key file for signing the cache";};};config = mkIf config.cache.enable {age.secrets.nixServeKey = {rekeyFile = config.cache.secretKeyFile;owner = "root";};services.nix-serve = enabled {package = pkgs.nix-serve-ng;secretKeyFile = config.age.secrets.nixServeKey.path;bindAddress = "127.0.0.1";port = config.cache.port;};services.nginx.virtualHosts.${config.cache.fqdn} = merge config.services.nginx.sslTemplate {locations."= /".return = "301 https://${domain}/404";locations."/".proxyPass = "http://127.0.0.1:${toString config.cache.port}";};};}
{ config, lib, ... }: letinherit (config.networking) domain;inherit (lib) mkValue;in {options.security.acme.users = mkValue [];config.users.groups.acme.members = config.security.acme.users;config.security.acme = {acceptTerms = true;defaults = {environmentFile = config.age.secrets.acmeEnvironment.path;dnsProvider = "cloudflare";dnsResolver = "1.1.1.1";email = "security@${domain}";};certs.${domain} = {extraDomainNames = [ "*.${domain}" ];group = "acme";};};}