nixos/system/machines/server/modules/nginx/default.nix
Bryan Ramos 6692807229 updated
2026-04-13 15:57:27 -04:00

158 lines
4.1 KiB
Nix

{ pkgs, lib, config, ... }:
with lib;
let
cfg = config.modules.system.nginx;
domain = "ramos.codes";
privateAccessRules = concatMapStringsSep "\n" (cidr: "allow ${cidr};") cfg.privateAllowCidrs + "\ndeny all;";
in
{
options.modules.system.nginx = {
enable = mkEnableOption "Nginx Reverse Proxy";
privateAllowCidrs = mkOption {
type = types.listOf types.str;
default = [
"192.168.0.0/24"
"10.8.0.0/24"
];
description = ''
CIDR ranges allowed to access private vhosts (LAN + WireGuard).
'';
};
searxng.enable = mkEnableOption "Publicly exposed SearXNG endpoint with secret path via sops";
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 80 443 ];
systemd.services.nginx.serviceConfig.LimitNOFILE = 65536;
environment.etc."fail2ban/filter.d/nginx-404.conf".text = ''
[Definition]
failregex = ^<HOST> - .+ "(GET|POST|HEAD|PUT|DELETE|PATCH) .+ HTTP/[0-9.]+" 404
ignoreregex =
'';
environment.etc."fail2ban/filter.d/nginx-401.conf".text = ''
[Definition]
failregex = ^<HOST> - .+ "(GET|POST|HEAD|PUT|DELETE|PATCH) .+ HTTP/[0-9.]+" 401
ignoreregex =
'';
services.fail2ban.jails.nginx-404 = ''
enabled = true
filter = nginx-404
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 10m
bantime = 24h
'';
services.fail2ban.jails.nginx-401 = ''
enabled = true
filter = nginx-401
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 10m
bantime = 24h
'';
security.acme = {
acceptTerms = true;
defaults.email = config.user.email;
certs."${domain}" = {
domain = "*.${domain}";
dnsProvider = "namecheap";
environmentFile = "/var/lib/acme/namecheap.env";
group = "nginx";
};
};
services.nginx = {
enable = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
eventsConfig = "worker_connections 4096;";
# Catch-all default - friendly error for unknown subdomains
virtualHosts."_" = {
default = true;
useACMEHost = domain;
forceSSL = true;
locations."/" = {
return = "404 'Not Found: This subdomain does not exist.'";
extraConfig = ''
add_header Content-Type text/plain;
'';
};
};
virtualHosts."test.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
return = "200 'nginx is working'";
extraConfig = ''
add_header Content-Type text/plain;
'';
};
};
virtualHosts."wg.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString config.modules.system.wstunnel.listenPort}";
proxyWebsockets = true;
extraConfig = ''
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
'';
};
};
virtualHosts."searxng.${domain}" = mkIf cfg.searxng.enable {
useACMEHost = domain;
forceSSL = true;
locations."/".return = "404";
extraConfig = ''
include ${config.sops.templates."nginx-searxng-location.conf".path};
'';
};
virtualHosts."chat.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.0.23:3080";
proxyWebsockets = true;
extraConfig = privateAccessRules;
};
};
virtualHosts."ai.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.0.23:8000";
proxyWebsockets = true;
};
};
virtualHosts."comfy.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.0.23:8188";
proxyWebsockets = true;
extraConfig = privateAccessRules;
};
};
};
};
}