My Nix Configuration
1{ pkgs, lib, ... }: 2let 3 pns = lib.py.data.services; 4 mail = lib.py.data.mail; 5 marvin = "http://${lib.py.data.hosts.marvin.ts.ip4}"; 6 marvinIP = lib.py.data.hosts.marvin.ts.ip4; 7 tsNet = lib.py.data.tsNet; 8in 9{ 10 services.caddy = { 11 enable = true; 12 package = pkgs.caddy.withPlugins { 13 plugins = [ 14 "github.com/caddy-dns/desec@v1.0.1" 15 "github.com/greenpau/caddy-security@v1.1.31" 16 "github.com/tailscale/caddy-tailscale@v0.0.0-20250207163903-69a970c84556" 17 "github.com/mholt/caddy-l4@v0.0.0-20250428144642-57989befb7e6" 18 "github.com/mohammed90/caddy-git-fs@v0.0.0-20240805164056-529acecd1830" 19 ]; 20 hash = "sha256-NPMrt7hARdnXP3xh4TRsc+TMpuXZzwY6zdrTw6E3nSM="; 21 }; 22 email = "pyrox@pyrox.dev"; 23 virtualHosts = { 24 # Redirect old domains -> pyrox.dev 25 "blog.pyrox.dev" = { 26 serverAliases = [ 27 "www.pyrox.dev" 28 "thehedgehog.me" 29 ]; 30 extraConfig = '' 31 redir https://pyrox.dev{uri} permanent 32 ''; 33 }; 34 "pyrox.dev" = { 35 extraConfig = '' 36 route { 37 header /.well-known/matrix/* Access-Control-Allow-Origin * 38 reverse_proxy /.well-known/matrix/* http://100.123.15.72:6922 39 redir /.well-known/carddav https://cloud.pyrox.dev/.well-known/carddav temporary 40 redir /.well-known/caldav https://cloud.pyrox.dev/.well-known/caldav temporary 41 header /.well-known/openpgpkey/* Access-Control-Allow-Origin * 42 header /.well-known/openpgpkey/hu/* application/octet-stream 43 respond /.well-known/openpgpkey/*/policy 200 44 header /.well-known/fursona Content-Type application/json 45 header { 46 X-Content-Type-Options nosniff 47 Permissions-Policy accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), unload=(), 48 +Permissions-Policy display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), 49 +Permissions-Policy gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), 50 +Permissions-Policy payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), 51 +Permissions-Policy sync-xhr=(self), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), 52 +Permissions-Policy clipboard-write=(), gamepad=(), hid=(), idle-detection=(), interest-cohort=(), serial=() 53 X-Frame-Options SAMEORIGIN 54 Referrer-Policy origin 55 -Server 56 } 57 file_server { 58 fs blog-repo 59 hide .git 60 precompressed br gzip 61 } 62 } 63 ''; 64 }; 65 66 # Authentication 67 ${pns.pocket-id.extUrl} = { 68 extraConfig = '' 69 reverse_proxy /api/* ${marvin}:${toString pns.pocket-id.be-port} { 70 header_up X-Real-IP {remote_host} 71 header_up X-Http-Version {http.request.proto} 72 } 73 reverse_proxy /.well-known/* ${marvin}:${toString pns.pocket-id.be-port} { 74 header_up X-Real-IP {remote_host} 75 header_up X-Http-Version {http.request.proto} 76 } 77 reverse_proxy /* ${marvin}:${toString pns.pocket-id.port} { 78 header_up X-Real-IP {remote_host} 79 header_up X-Http-Version {http.request.proto} 80 } 81 ''; 82 }; 83 84 # Vaultwarden 85 ${pns.vaultwarden.extUrl} = { 86 extraConfig = '' 87 header / { 88 Strict-Transport-Security "max-age=31536000;" 89 X-XSS-Protection "0" 90 X-Frame-Options "DENY" 91 X-Robots-Tag "noindex, nofollow" 92 X-Content-Type-Options "nosniff" 93 -Server 94 -X-Powered-By 95 -Last-Modified 96 } 97 reverse_proxy ${marvin}:${toString pns.vaultwarden.anubis} { 98 header_up X-Real-IP {remote_host} 99 header_up X-Http-Version {http.request.proto} 100 } 101 ''; 102 }; 103 104 # Cinny + Conduit 105 ${pns.matrix-server.extUrl} = { 106 extraConfig = '' 107 handle /_matrix/* { 108 reverse_proxy ${marvin}:${toString pns.matrix-server.port} 109 } 110 handle { 111 root * /var/www/cinny/dist/ 112 try_files {path} / index.html 113 file_server 114 } 115 ''; 116 }; 117 # Jellyfin 118 ${pns.jellyfin.extUrl} = { 119 extraConfig = '' 120 @blocked not remote_ip 100.64.0.0/10 private_ranges 121 reverse_proxy ${marvin}:${toString pns.jellyfin.port} 122 handle /metrics* { 123 respond @blocked "Access Denied" 403 124 } 125 ''; 126 }; 127 128 # MTA-STS Setup for mailserver 129 "mta-sts.pyrox.dev" = { 130 extraConfig = '' 131 header Content-Type text/plain; charset=utf-8 132 respond /.well-known/mta-sts.txt <<END 133 version: STSv1 134 mode: enforce 135 mx: mail.pyrox.dev 136 mx:mail2.pyrox.dev 137 max_age: 2419200 138 END 200 139 ''; 140 }; 141 142 # Yourmother.website 143 "yourmother.website" = { 144 extraConfig = '' 145 header Content-Type text/html 146 respond 200 { 147 body `<!DOCTYPE html> 148 <html> 149 <head> 150 <meta http-equiv="Refresh" content="0; url=https://youtube.com/watch?v=oHg5SJYRHA0" /> 151 </head> 152 </html>` 153 } 154 ''; 155 }; 156 157 # OpenPGP WKD stuff 158 "openpgpkey.pyrox.dev" = { 159 serverAliases = [ "openpgpkey.thehedgehog.me" ]; 160 extraConfig = '' 161 respond /.well-known/openpgpkey/{labels.1}.{labels.0}/policy 200 162 header Access-Control-Allow-Origin * 163 header /.well-known/openpgpkey/{labels.1}.{labels.0}/hu/* Content-Type application/octet-stream 164 file_server { 165 fs blog-repo 166 } 167 ''; 168 }; 169 170 # Metrics 171 ":6899" = { 172 extraConfig = '' 173 metrics /metrics 174 ''; 175 }; 176 # SIMPLE HOSTS 177 178 # Forgejo 179 ${pns.git.extUrl} = { 180 extraConfig = '' 181 reverse_proxy ${marvin}:${toString pns.git.anubis} { 182 header_up X-Real-Ip {remote_host} 183 header_up X-Http-Version {http.request.proto} 184 } 185 ''; 186 }; 187 188 # Grafana 189 ${pns.grafana.extUrl} = { 190 extraConfig = '' 191 reverse_proxy ${marvin}:${toString pns.grafana.anubis} { 192 header_up X-Real-Ip {remote_host} 193 header_up X-Http-Version {http.request.proto} 194 } 195 ''; 196 }; 197 198 # Miniflux 199 ${pns.miniflux.extUrl} = { 200 extraConfig = '' 201 reverse_proxy ${marvin}:${toString pns.miniflux.anubis} { 202 header_up X-Real-Ip {remote_host} 203 header_up X-Http-Version {http.request.proto} 204 } 205 ''; 206 }; 207 208 # Nextcloud 209 ${pns.nextcloud.extUrl} = { 210 extraConfig = '' 211 reverse_proxy ${marvin}:${toString pns.nextcloud.anubis} { 212 header_up X-Real-Ip {remote_host} 213 header_up X-Http-Version {http.request.proto} 214 } 215 ''; 216 }; 217 218 # Nextcloud-Office(Collabora) 219 ${pns.nextcloud-office.extUrl} = { 220 extraConfig = '' 221 reverse_proxy ${marvin}:${toString pns.nextcloud-office.anubis} { 222 header_up X-Real-Ip {remote_host} 223 header_up X-Http-Version {http.request.proto} 224 } 225 ''; 226 }; 227 228 # Planka 229 ${pns.planka.extUrl} = { 230 extraConfig = '' 231 reverse_proxy ${marvin}:${toString pns.planka.anubis} { 232 header_up X-Real-Ip {remote_host} 233 header_up X-Http-Version {http.request.proto} 234 } 235 ''; 236 }; 237 238 # Pingvin Share 239 ${pns.pingvin-share.extUrl} = { 240 extraConfig = '' 241 reverse_proxy /api/* ${marvin}:${toString pns.pingvin-share.be-anubis} { 242 header_up X-Real-IP {remote_host} 243 header_up X-Http-Version {http.request.proto} 244 } 245 reverse_proxy /* ${marvin}:${toString pns.pingvin-share.anubis} { 246 header_up X-Real-IP {remote_host} 247 header_up X-Http-Version {http.request.proto} 248 } 249 ''; 250 }; 251 252 # Simple Tailscale Hosts 253 254 # Deemix 255 "${pns.deemix.tsHost}.${tsNet}" = { 256 extraConfig = '' 257 bind tailscale/${pns.deemix.tsHost} 258 tailscale_auth 259 reverse_proxy ${marvin}:${toString pns.deemix.port} 260 ''; 261 }; 262 # Pinchflat 263 "${pns.pinchflat.tsHost}.${tsNet}" = { 264 extraConfig = '' 265 bind tailscale/${pns.pinchflat.tsHost} 266 tailscale_auth 267 reverse_proxy ${marvin}:${toString pns.pinchflat.port} 268 ''; 269 }; 270 # "mail.pyrox.dev:80" = { 271 # extraConfig = '' 272 # reverse_proxy ${marvin}:${mail.intHTTP} 273 # ''; 274 # }; 275 }; 276 # Mail Config 277 globalConfig = '' 278 filesystem blog-repo git ${marvin}:${toString pns.git.port}/pyrox/new-blog { 279 ref refs/heads/pages 280 refresh_period 10m 281 } 282 ''; 283 # layer4 { 284 # 0.0.0.0:465 { 285 # route { 286 # proxy { 287 # proxy_protocol v2 288 # upstream ${marvinIP}:${mail.intSMTPS} 289 # } 290 # } 291 # } 292 # 0.0.0.0:993 { 293 # route { 294 # proxy { 295 # proxy_protocol v2 296 # upstream ${marvinIP}:${mail.intIMAPS} 297 # } 298 # } 299 # } 300 # 0.0.0.0:4190 { 301 # route { 302 # proxy { 303 # proxy_protocol v2 304 # upstream ${marvinIP}:${mail.intManageSieve} 305 # } 306 # } 307 # } 308 # } 309 }; 310 systemd.services.caddy.serviceConfig.CapabilityBoundingSet = "CAP_NET_BIND_SERVICE"; 311 systemd.services.caddy.serviceConfig.AmbientCapabilities = "CAP_NET_BIND_SERVICE"; 312}