Files
haschel/modules/proxy.nix
2026-03-07 17:11:00 -07:00

215 lines
6.5 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
atriDotDad = "atri.dad";
atashDotDev = "atash.dev";
matrixDomain = "matrix.${atriDotDad}";
matrixRtcDomain = "matrixrtc.${atriDotDad}";
upstream = "lloyd.tadpole-pain.ts.net";
streamPorts = [
69
420
25565
25566
25567
];
wellKnownServer = builtins.toJSON {
"m.server" = "${matrixDomain}:443";
};
wellKnownClient = builtins.toJSON {
"m.homeserver" = {
base_url = "https://${matrixDomain}";
};
"org.matrix.msc4143.rtc_foci" = [
{
type = "livekit";
livekit_service_url = "https://${matrixDomain}/livekit/jwt";
}
];
};
mkProxy = port: config_preset: ''
import ${config_preset}
reverse_proxy http://${upstream}:${toString port}
'';
mkSocatService =
port: proto:
lib.nameValuePair "socat-${proto}-${toString port}" {
description = "Socat ${proto} proxy for port ${toString port}";
after = [
"network-online.target"
"tailscaled.service"
];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.socat}/bin/socat ${lib.toUpper proto}-LISTEN:${toString port},fork,reuseaddr ${lib.toUpper proto}:${upstream}:${toString port}";
Restart = "on-failure";
RestartSec = "5s";
DynamicUser = true;
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
};
};
in
{
services.caddy = {
enable = true;
email = "me@${atriDotDad}";
package = pkgs.caddy.withPlugins {
plugins = [ "pkg.jsn.cam/caddy-defender@v0.10.0" ];
hash = "sha256-DpCaOp9pXV3sdMz1hh/1SQ7ww7Fo4aAgLvFyQFgIJdI=";
};
extraConfig = ''
(common_config) {
encode zstd gzip
defender garbage {
ranges openai deepseek aliyun azurepubliccloud aws gcloud githubcopilot mistral oci vultr digitalocean linode cloudflare
}
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://*.atri.dad https://*.atash.dev; font-src 'self' data:; connect-src 'self' wss: https://*.atri.dad https://*.atash.dev; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"
-Server
-alt-svc
}
}
(relaxed_config) {
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' wss: https://*.atri.dad https://*.atash.dev; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"
-Server
-alt-svc
}
}
${atriDotDad} {
import common_config
handle /.well-known/matrix/server {
header Content-Type application/json
header X-Content-Type-Options nosniff
respond `${wellKnownServer}` 200
}
handle /.well-known/matrix/client {
header Content-Type application/json
header Access-Control-Allow-Origin "*"
header Vary Origin
header X-Content-Type-Options nosniff
respond `${wellKnownClient}` 200
}
handle {
reverse_proxy http://${upstream}:3000
}
}
analytics.${atriDotDad} { ${mkProxy 30060 "common_config"} }
ascently.${atriDotDad} { ${mkProxy 8838 "common_config"} }
chef.${atriDotDad} { ${mkProxy 30111 "common_config"} }
democlimb.${atriDotDad} { ${mkProxy 8008 "common_config"} }
fedi.${atriDotDad} { ${mkProxy 8181 "common_config"} }
gist.${atriDotDad} { ${mkProxy 1227 "common_config"} }
git.${atriDotDad} { ${mkProxy 30010 "common_config"} }
links.${atriDotDad} { ${mkProxy 30243 "common_config"} }
memos.${atriDotDad} { ${mkProxy 30311 "common_config"} }
mermaid.${atriDotDad} { ${mkProxy 8280 "relaxed_config"} }
msrc.${atriDotDad} { ${mkProxy 3311 "common_config"} }
openclimb.${atriDotDad} { ${mkProxy 1337 "common_config"} }
photos.${atriDotDad} { ${mkProxy 30041 "common_config"} }
pods.${atriDotDad} { ${mkProxy 30067 "common_config"} }
requests.${atriDotDad} { ${mkProxy 30042 "common_config"} }
s3.${atriDotDad} { ${mkProxy 30188 "common_config"} }
search.${atriDotDad} { ${mkProxy 30053 "relaxed_config"} }
vault.${atriDotDad} { ${mkProxy 30032 "common_config"} }
vids.${atriDotDad} { ${mkProxy 31008 "common_config"} }
music.${atriDotDad} { ${mkProxy 30043 "common_config"} }
books.${atriDotDad} { ${mkProxy 31067 "common_config"} }
tv.${atriDotDad} { ${mkProxy 30013 "common_config"} }
ripkyle.org { ${mkProxy 4321 "common_config"} }
${atashDotDev} { ${mkProxy 6969 "common_config"} }
chronus.${atashDotDev} { ${mkProxy 7337 "common_config"} }
${matrixDomain} {
request_body {
max_size 1GB
}
handle_path /livekit/jwt/* {
@allowed path /sfu/get /get_token /healthz
handle @allowed {
reverse_proxy http://[::1]:${toString config.services.lk-jwt-service.port}
}
handle {
respond 404
}
}
handle {
reverse_proxy http://[::1]:6167
}
}
${matrixRtcDomain} {
handle /.well-known/acme-challenge/* {
root * /var/lib/acme/acme-challenge
file_server
}
handle {
reverse_proxy http://[::1]:${toString config.services.livekit.settings.port} {
flush_interval -1
}
}
}
'';
};
systemd.services = lib.listToAttrs (
(map (port: mkSocatService port "tcp") streamPorts)
++ (map (port: mkSocatService port "udp") streamPorts)
);
networking.firewall = {
allowedTCPPorts = [
80
443
]
++ streamPorts;
allowedUDPPorts = streamPorts;
};
security.acme = {
acceptTerms = true;
defaults.email = "me@${atriDotDad}";
certs."${matrixRtcDomain}" = {
webroot = "/var/lib/acme/acme-challenge";
};
};
}