nixos-config/hosts/crossbox/nginx.nix

175 lines
4.9 KiB
Nix

{ config, pkgs, lib, ... }:
let
# NOTE: API keys will be loaded from /srv/nginx/secrets at runtime
# This file should contain one Bearer token per line
# The secrets file is read at runtime via include directive instead of build time
# to avoid flake purity issues
in
{
services.nginx = {
enable = true;
# Recommended settings
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
# Increase bucket size for long Bearer tokens
mapHashBucketSize = 128;
# Map directive to check Authorization header against multiple keys
# Keys are loaded from /srv/nginx/secrets.map at runtime
appendHttpConfig = ''
# Check if the Authorization header matches any expected value
map $http_authorization $auth_status {
default "unauthorized";
"" "no_auth";
# Add your Bearer tokens here manually, or use include directive
# Format: "Bearer YOUR_TOKEN_HERE" "authorized";
# You can also create /srv/nginx/secrets.map and include it:
# include /srv/nginx/secrets.map;
}
'';
# Virtual hosts configuration
virtualHosts = {
# Main website - Static HTML/CSS
"www.binning.net" = {
forceSSL = true;
#enableACME = true;
sslCertificate = "/srv/nginx/binning.net.pem";
sslCertificateKey = "/srv/nginx/binning.net.key.pem";
root = "/srv/www/binning.net";
locations."/" = {
index = "index.html";
tryFiles = "$uri $uri/ =404";
extraConfig = ''
# Enable Server Side Includes for navbar/footer includes
ssi on;
'';
};
# Private blog articles with HTTP basic authentication
locations."/blog/private/" = {
extraConfig = ''
auth_basic "Private Articles";
auth_basic_user_file "/srv/nginx/.htpasswd";
# Enable Server Side Includes
ssi on;
'';
};
# Optional: Custom 404 page
extraConfig = ''
error_page 404 /404.html;
'';
};
# Ollama with Bearer token authentication
"ollama.binning.net" = {
forceSSL = true;
#enableACME = true;
sslCertificate = "/srv/nginx/binning.net.pem";
sslCertificateKey = "/srv/nginx/binning.net.key.pem";
locations."/" = {
extraConfig = ''
# Check auth status
if ($auth_status = "no_auth") {
return 401 "Unauthorized: Bearer token required\n";
}
if ($auth_status = "unauthorized") {
return 403 "Forbidden: Invalid API key\n";
}
# Proxy to Ollama (only if authorized)
proxy_pass http://localhost:11434;
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;
# Timeouts for long-running requests
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
# Allow large request bodies
client_max_body_size 100M;
# Logging
access_log /var/log/nginx/ollama_access.log;
error_log /var/log/nginx/ollama_error.log;
'';
};
};
# Forgejo
"forgejo.binning.net" = {
forceSSL = true;
#enableACME = true;
sslCertificate = "/srv/nginx/binning.net.pem";
sslCertificateKey = "/srv/nginx/binning.net.key.pem";
locations."/" = {
proxyPass = "http://127.0.0.1:3000";
# No extraConfig needed - recommendedProxySettings handles headers
};
};
# Radicale
"radicale.binning.net" = {
forceSSL = true;
#enableACME = true;
sslCertificate = "/srv/nginx/binning.net.pem";
sslCertificateKey = "/srv/nginx/binning.net.key.pem";
locations."/" = {
proxyPass = "http://127.0.0.1:5232";
# recommendedProxySettings handles most headers
extraConfig = ''
proxy_set_header X-Script-Name "";
'';
};
};
# DocuSeal
"docuseal.binning.net" = {
forceSSL = true;
#enableACME = true;
sslCertificate = "/srv/nginx/binning.net.pem";
sslCertificateKey = "/srv/nginx/binning.net.key.pem";
locations."/" = {
proxyPass = "http://127.0.0.1:3030";
proxyWebsockets = true;
};
};
};
};
# Firewall
networking.firewall.allowedTCPPorts = [ 80 443 ];
# ACME/Let's Encrypt
security.acme = {
acceptTerms = true;
defaults.email = "hvanb@pm.me";
};
# Ensure the data directory exists with proper permissions
systemd.tmpfiles.rules = [
"d /var/lib/www 0750 nginx nginx -"
];
}