All checks were successful
Build Nix modules (dry-run) / build-modules (push) Successful in 3m26s
373 lines
11 KiB
Nix
373 lines
11 KiB
Nix
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}: let
|
|
choose = paths: builtins.head (builtins.filter (p: builtins.pathExists p) paths);
|
|
in {
|
|
options.local = {
|
|
hostname = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "nixos-default";
|
|
description = "System hostname";
|
|
};
|
|
username = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "user";
|
|
description = "Primary user username";
|
|
};
|
|
userDescription = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "NixOS User";
|
|
description = "Primary user description";
|
|
};
|
|
address = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "10.1.1.100";
|
|
description = "Static IP address";
|
|
};
|
|
};
|
|
|
|
imports = [
|
|
(choose [./modules/desktop-manager/sway_greetd_homemanager.nix ../desktop-manager/sway_greetd_homemanager.nix])
|
|
(choose [./modules/local/hostname_username.nix ../local/hostname_username.nix])
|
|
(choose [./modules/local/networking_local.nix ../local/networking_local.nix])
|
|
(choose [./modules/bootloader/seabios-assigned-iso-at-birth.nix ../bootloader/seabios-assigned-iso-at-birth.nix])
|
|
(choose [./modules/lix-default.nix ../lix-default.nix])
|
|
# Optionally: (choose [ ./modules/toolsets/remote_building.nix ../toolsets/remote_building.nix ])
|
|
];
|
|
|
|
config = {
|
|
local.hostname = "nixos-traefik";
|
|
local.username = "traefikprg";
|
|
local.userDescription = "NixOS PRG Traefik Service";
|
|
local.address = "10.1.1.250";
|
|
|
|
# Configure Anubis service
|
|
services.anubis = {
|
|
instances = {
|
|
"" = {
|
|
enable = true;
|
|
settings = {
|
|
# Bind to TCP instead of Unix socket for Docker-style integration
|
|
BIND_NETWORK = "tcp";
|
|
BIND = "127.0.0.1:8090";
|
|
|
|
# Empty TARGET for redirect mode
|
|
TARGET = " ";
|
|
|
|
# Configure redirect domains - ALL domains that should be able to redirect back after challenge
|
|
REDIRECT_DOMAINS = "prg-radio.org,git.prg-radio.org,wavelog.prg-radio.org,partdb.prg-radio.org,anubis.prg-radio.org";
|
|
|
|
# Public URL for Anubis
|
|
PUBLIC_URL = "https://anubis.prg-radio.org";
|
|
|
|
# Cookie domain for proper scoping (leading dot for all subdomains)
|
|
COOKIE_DOMAIN = ".prg-radio.org";
|
|
|
|
# Difficulty level
|
|
DIFFICULTY = 7;
|
|
#ALGOTIHM = "slow";
|
|
|
|
# Optional: serve robots.txt
|
|
SERVE_ROBOTS_TXT = true;
|
|
|
|
# Optional: webmaster email for error pages
|
|
WEBMASTER_EMAIL = "dtu.prg@gmail.com";
|
|
|
|
# Metrics on separate port
|
|
METRICS_BIND_NETWORK = "tcp";
|
|
METRICS_BIND = "127.0.0.1:8091";
|
|
};
|
|
};
|
|
|
|
# Per-service Anubis instances (reverse-proxy mode) ---------------------------
|
|
forgejo = {
|
|
enable = true;
|
|
settings = {
|
|
BIND_NETWORK = "tcp";
|
|
BIND = "127.0.0.1:8092";
|
|
TARGET = "http://10.1.1.4:3000"; # Forgejo backend
|
|
DIFFICULTY = 20;
|
|
SERVE_ROBOTS_TXT = true;
|
|
WEBMASTER_EMAIL = "dtu.prg@gmail.com";
|
|
METRICS_BIND_NETWORK = "tcp";
|
|
METRICS_BIND = "127.0.0.1:8095";
|
|
};
|
|
};
|
|
|
|
/*
|
|
wavelog = {
|
|
enable = true;
|
|
settings = {
|
|
BIND_NETWORK = "tcp";
|
|
BIND = "127.0.0.1:8093";
|
|
TARGET = "http://10.1.1.249:8086"; # Wavelog backend
|
|
DIFFICULTY = 20;
|
|
SERVE_ROBOTS_TXT = true;
|
|
WEBMASTER_EMAIL = "dtu.prg@gmail.com";
|
|
METRICS_BIND_NETWORK = "tcp";
|
|
METRICS_BIND = "127.0.0.1:8096";
|
|
};
|
|
};
|
|
*/
|
|
|
|
# This part needs investigating
|
|
partdb = {
|
|
enable = true;
|
|
settings = {
|
|
BIND_NETWORK = "tcp";
|
|
BIND = "127.0.0.1:8094";
|
|
TARGET = "http://10.1.1.249:8087"; # PartDB backend
|
|
DIFFICULTY = 20;
|
|
SERVE_ROBOTS_TXT = true;
|
|
WEBMASTER_EMAIL = "dtu.prg@gmail.com";
|
|
METRICS_BIND_NETWORK = "tcp";
|
|
METRICS_BIND = "127.0.0.1:8097";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
services.traefik = {
|
|
enable = true;
|
|
group = "acme";
|
|
staticConfigOptions = {
|
|
entryPoints = {
|
|
web = {
|
|
# Bind on IPv6 as well as IPv4 by using [::]:80
|
|
address = "[::]:80";
|
|
asDefault = true;
|
|
http.redirections.entrypoint = {
|
|
to = "websecure";
|
|
scheme = "https";
|
|
};
|
|
};
|
|
websecure = {
|
|
# Bind on IPv6 as well as IPv4 by using [::]:443
|
|
address = "[::]:443";
|
|
asDefault = true;
|
|
http.tls = {
|
|
domains = [
|
|
{
|
|
main = "prg-radio.org";
|
|
sans = ["*.prg-radio.org"];
|
|
}
|
|
];
|
|
};
|
|
};
|
|
# Federation entrypoint: external TLS on 8448
|
|
federation = {
|
|
# Bind on IPv6 as well as IPv4 by using [::]:8448
|
|
address = "[::]:8448";
|
|
};
|
|
# TeamSpeak entry points
|
|
teamspeak-voice = {
|
|
# UDP entrypoint bind to IPv6 as well
|
|
address = "[::]:9987/udp";
|
|
};
|
|
teamspeak-squery = {
|
|
address = "[::]:10022/tcp";
|
|
};
|
|
teamspeak-data = {
|
|
address = "[::]:30033/tcp";
|
|
};
|
|
};
|
|
log = {
|
|
level = "INFO";
|
|
filePath = "${config.services.traefik.dataDir}/traefik.log";
|
|
format = "json";
|
|
};
|
|
api.dashboard = true;
|
|
api.insecure = true;
|
|
};
|
|
dynamicConfigOptions = {
|
|
tls.certificates = [
|
|
{
|
|
certFile = "/var/lib/acme/prg-radio.org/cert.pem";
|
|
keyFile = "/var/lib/acme/prg-radio.org/key.pem";
|
|
}
|
|
];
|
|
|
|
http.routers = {
|
|
#anubis-api = {
|
|
# rule = "Host(`anubis.prg-radio.org`) && PathPrefix(`/.within.website/x/cmd/anubis/api`)";
|
|
# service = "anubis";
|
|
# entryPoints = ["websecure"];
|
|
# priority = 200;
|
|
# tls = {};
|
|
# };
|
|
|
|
# Anubis router (for challenge page)
|
|
anubis = {
|
|
rule = "Host(`anubis.prg-radio.org`)";
|
|
service = "anubis";
|
|
entryPoints = ["websecure"];
|
|
tls = {};
|
|
};
|
|
|
|
# Protected service example: Forgejo
|
|
forgejo = {
|
|
rule = "Host(`git.prg-radio.org`)";
|
|
service = "forgejo";
|
|
entryPoints = ["websecure"];
|
|
tls = {};
|
|
};
|
|
|
|
# Matrix HTTP router for client requests (Element etc.)
|
|
matrix = {
|
|
rule = "Host(`lgbtq.prg-radio.org`)";
|
|
service = "matrix";
|
|
entryPoints = ["websecure"];
|
|
tls = {};
|
|
};
|
|
|
|
# Protected service: Wavelog
|
|
wavelog = {
|
|
rule = "Host(`wavelog.prg-radio.org`)";
|
|
service = "wavelog";
|
|
entryPoints = ["websecure"];
|
|
tls = {};
|
|
};
|
|
|
|
# Protected service: PartDB
|
|
partdb = {
|
|
rule = "Host(`partdb.prg-radio.org`)";
|
|
service = "partdb";
|
|
entryPoints = ["websecure"];
|
|
tls = {};
|
|
};
|
|
};
|
|
|
|
http.services = {
|
|
# Anubis service (challenge UI / redirect endpoint)
|
|
anubis.loadBalancer = {
|
|
servers = [
|
|
{url = "http://127.0.0.1:8090";}
|
|
];
|
|
#passHostHeader = true;
|
|
};
|
|
|
|
forgejo.loadBalancer = {
|
|
servers = [
|
|
{url = "http://127.0.0.1:8092";}
|
|
];
|
|
};
|
|
matrix.loadBalancer = {
|
|
servers = [
|
|
{url = "http://10.1.1.248:12244";}
|
|
];
|
|
};
|
|
wavelog.loadBalancer = {
|
|
servers = [
|
|
{url = "http://10.1.1.249:8086";}
|
|
];
|
|
};
|
|
|
|
partdb.loadBalancer = {
|
|
servers = [
|
|
{url = "http://127.0.0.1:8094";}
|
|
];
|
|
};
|
|
};
|
|
|
|
# TCP routing for TeamSpeak
|
|
tcp.routers = {
|
|
teamspeak-squery = {
|
|
rule = "HostSNI(`*`)";
|
|
service = "teamspeak-squery";
|
|
entryPoints = ["teamspeak-squery"];
|
|
};
|
|
teamspeak-data = {
|
|
rule = "HostSNI(`*`)";
|
|
service = "teamspeak-data";
|
|
entryPoints = ["teamspeak-data"];
|
|
};
|
|
# Federation TCP router: incoming on :8448 -> Conduit backend
|
|
matrix-federation = {
|
|
rule = "HostSNI(`*`)";
|
|
service = "matrix-federation";
|
|
entryPoints = ["federation"];
|
|
# Pass TLS through to the backend (Conduit handles TLS on port 12244)
|
|
tls = {
|
|
passthrough = true;
|
|
};
|
|
};
|
|
# Also accept TLS passthrough on port 443 for the Matrix host so
|
|
# other servers that contact :443/_matrix/*
|
|
# will be forwarded to Conduit as well.
|
|
# I guess I had to declare the rule explicitly here again?
|
|
matrix-tls443 = {
|
|
# match by SNI to avoid interfering with other HTTPS sites
|
|
rule = "HostSNI(`lgbtq.prg-radio.org`)";
|
|
service = "matrix-federation";
|
|
entryPoints = ["websecure"];
|
|
tls = {
|
|
passthrough = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
tcp.services = {
|
|
teamspeak-squery.loadBalancer = {
|
|
servers = [
|
|
{address = "10.1.1.248:10022";}
|
|
];
|
|
};
|
|
teamspeak-data.loadBalancer = {
|
|
servers = [
|
|
{address = "10.1.1.248:30033";}
|
|
];
|
|
};
|
|
matrix-federation.loadBalancer = {
|
|
servers = [
|
|
{address = "10.1.1.248:12244";}
|
|
];
|
|
};
|
|
};
|
|
|
|
# UDP routing for TeamSpeak voice
|
|
udp.routers = {
|
|
teamspeak-voice = {
|
|
entryPoints = ["teamspeak-voice"];
|
|
service = "teamspeak-voice";
|
|
};
|
|
};
|
|
|
|
udp.services = {
|
|
teamspeak-voice.loadBalancer = {
|
|
servers = [
|
|
{address = "10.1.1.248:9987";}
|
|
];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
defaults.email = "dtu.prg@gmail.com";
|
|
certs."prg-radio.org" = {
|
|
domain = "*.prg-radio.org";
|
|
group = "acme";
|
|
dnsProvider = "cloudflare";
|
|
environmentFile = "/home/traefikprg/cloudflare/cloudflare.env";
|
|
reloadServices = ["traefik.service"];
|
|
};
|
|
};
|
|
|
|
# Enable Tailscale for remote access to Traefik dashboard and configuration
|
|
services.tailscale.enable = true;
|
|
|
|
systemd.services.traefik = {
|
|
after = ["acme-finished-prg-radio.org.target"];
|
|
wants = ["acme-finished-prg-radio.org.target"];
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = [80 443 10022 30033 8448];
|
|
networking.firewall.allowedUDPPorts = [80 443 9987];
|
|
|
|
system.stateVersion = "25.11";
|
|
};
|
|
}
|