devops/modules/meos-gateway.nix
Marcus (agent-cos) 7b5ffe6b11 Initial cluster config: NixOS flake + k3s + 5 node definitions
- Multi-host flake.nix (3x N97 x86_64 + 2x RPi4 aarch64)
- Shared modules: k3s-cluster, tailscale, meos-gateway
- Node configs: n97-1 (control plane), n97-2/n97-3 (Ollama workers), rpi4-1/rpi4-2 (ARM workers)
- K8s manifests: Forgejo, Postgres (CNPG), Umami, OpenBrain, MeOS Dashboard, MCP servers
- Bootstrap and DB migration scripts
- Migration plan doc (7-day phased rollout)
2026-05-04 12:22:09 -07:00

94 lines
3 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.meos-gateway;
certDir = config.security.acme.certs."os.scoble.me".directory;
in {
options.services.meos-gateway = {
enable = mkEnableOption "MeOS Gateway — nginx reverse proxy for os.scoble.me";
tailscaleIP = mkOption {
type = types.str;
description = "n97-1 Tailscale IP for nginx to bind to.";
};
};
config = mkIf cfg.enable {
# ── Nginx — SSL-terminating reverse proxy ──
services.nginx = {
enable = true;
virtualHosts."os.scoble.me" = {
addSSL = true;
sslCertificate = "${certDir}/fullchain.pem";
sslCertificateKey = "${certDir}/key.pem";
listen = [
{ addr = cfg.tailscaleIP; port = 443; ssl = true; }
];
locations = {
"/forgejo/" = {
proxyPass = "http://k3s-forgejo.kube-system.svc.cluster.local:3000/";
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_set_header X-Forwarded-Prefix /forgejo;
'';
};
"/umami" = {
proxyPass = "http://k3s-umami.kube-system.svc.cluster.local:8069";
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;
'';
};
"/umami/" = {
proxyPass = "http://k3s-umami.kube-system.svc.cluster.local:8069";
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;
'';
};
"/dashboard/" = {
proxyPass = "http://k3s-dashboard.kube-system.svc.cluster.local:3000/";
proxyWebsockets = true;
};
"/" = {
proxyPass = "http://127.0.0.1:8082";
proxyWebsockets = true;
};
};
};
# HTTP -> HTTPS redirect
virtualHosts."os.scoble.me-http" = {
listen = [ { addr = cfg.tailscaleIP; port = 80; } ];
serverName = "os.scoble.me";
extraConfig = "return 301 https://$server_name$request_uri;";
};
};
# ACME with Cloudflare DNS challenge
security.acme = {
acceptTerms = true;
defaults.email = "scott@scoble.me";
certs."os.scoble.me" = {
dnsProvider = "cloudflare";
environmentFile = "/var/lib/acme/cloudflare.env";
group = "nginx";
};
};
# Firewall
networking.firewall.allowedTCPPorts = [ 80 443 ];
};
}