{ config, pkgs, lib, inputs, ... }: with lib; let cfg = config.custom.services.nginx; in { options.custom.services.nginx = { enable = mkEnableOption "Enables nginx"; https = mkOption { type = types.bool; default = true; description = "Should it use https?"; }; }; config = lib.mkIf cfg.enable { networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedUDPPorts = [ 80 443 ]; age.secrets.stash-auth = { file = ../../secrets/stash-auth.age; owner = "nginx"; }; systemd.tmpfiles.rules = [ "d /var/www 0740 nginx nginx -" "d /var/www/misc-files 0740 nginx nginx -" ]; services.nginx = { enable = true; additionalModules = [ pkgs.nginxModules.moreheaders pkgs.nginxModules.fancyindex ]; # Use recommended settings recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; statusPage = lib.mkIf config.services.prometheus.exporters.nginx.enable true; # Only allow PFS-enabled ciphers with AES256 sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; appendHttpConfig = '' more_set_headers 'Strict-Transport-Security: max-age=31536000; includeSubDomains'; more_set_headers 'X-XSS-Protection 1; mode=block'; # add_header X-Frame-Options 'ALLOW-FROM kopatz.ddns.net'; more_set_headers 'X-Content-Type-Options nosniff'; more_set_headers "Content-Security-Policy: frame-ancestors https://kopatz.ddns.net https://kop.oasch.net https://kopatz.dev"; more_set_headers "Referrer-Policy: same-origin"; more_set_headers "Permissions-Policy: geolocation=(), microphone=()"; ''; virtualHosts = let kopConfig = { root = pkgs.kop-website; forceSSL = cfg.https; enableACME = cfg.https; quic = cfg.https; http3 = cfg.https; locations = { "~* ^/assets/.*\\.(jpg|png)$".extraConfig = '' add_header Access-Control-Allow-Origin *; ''; "/stash" = { basicAuthFile = config.age.secrets.stash-auth.path; extraConfig = '' client_max_body_size 20000M; proxy_redirect off; 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_set_header X-NginX-Proxy true; proxy_pass http://localhost:7777; ''; }; "/stash/files" = { extraConfig = '' proxy_redirect off; 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_set_header X-NginX-Proxy true; proxy_pass http://localhost:7777; ''; }; "/tracker-site" = { tryFiles = "$uri $uri/ /tracker-site/index.html =404"; }; "/tracker-site/api" = { extraConfig = '' rewrite /tracker-site/api/(.*) /$1 break; ''; proxyPass = "http://127.0.0.1:8080"; }; "/radicale/" = { extraConfig = '' proxy_set_header X-Script-Name /radicale; ''; proxyPass = "http://localhost:5232/"; }; "/socket.io" = { proxyPass = "http://localhost:9955"; proxyWebsockets = true; }; "/comms/" = { extraConfig = '' more_set_headers "Permissions-Policy: geolocation=(), microphone=(self), camera=(self)"; ''; alias = "/comms/"; tryFiles = "$uri $uri/ /comms/index.html"; }; "/comms" = { extraConfig = '' return 301 /comms/; ''; }; "/kavita-client" = { extraConfig = '' return 301 /kavita-client/; ''; }; "/kavita-client/" = { alias = "/kavita-client/"; }; "/misc-files/" = { alias = "/var/www/misc-files/"; }; "/javaland/" = { alias = "/var/www/javaland/"; extraConfig = '' fancyindex on; fancyindex_hide_parent_dir on; fancyindex_exact_size off; ''; }; "/comms2/api" = { extraConfig = '' client_max_body_size 20000M; rewrite /comms2/api/(.*) /$1 break; ''; proxyPass = "http://localhost:3200/"; proxyWebsockets = true; }; "/comms2" = { extraConfig = '' return 301 /comms2/; ''; }; "/comms2/" = { extraConfig = '' more_set_headers "Permissions-Policy: geolocation=(), microphone=(self), camera=(self)"; ''; alias = "/var/www/discord-clone/"; tryFiles = "$uri $uri/ /var/www/discord-clone/index.html"; }; }; }; in { "kop.oasch.net" = kopConfig; "kop.bobin.at" = kopConfig; "kopatz.dev" = kopConfig; }; }; }; }