yep, more dotfiles

weird-row-server: add gatus instance

wiro.world 23276d93 184724e4

verified
+216 -118
+11
globals.nix
··· 11 11 matrix = "matrix.${wiro-world}"; 12 12 miniflux = "news.${wiro-world}"; 13 13 pds = "pds.${wiro-world}"; 14 + status = "status.${wiro-world}"; 15 + status' = "status.status.${wiro-world}"; 14 16 tangled-knot = "knot.${wiro-world}"; 15 17 tangled-spindle = "spindle.${wiro-world}"; 16 18 vaultwarden = "vault.${wiro-world}"; ··· 24 26 25 27 hbt-main = hypixel-bank-tracker; 26 28 hbt-banana = "banana.${hypixel-bank-tracker}"; 29 + }; 30 + 31 + hosts = { 32 + weird-row-server = { 33 + ip = "91.99.55.74"; 34 + ip-prefix-length = 1; 35 + ip6 = "2a01:4f8:c2c:76d2::1"; 36 + ip6-prefix-length = 64; 37 + }; 27 38 }; 28 39 }
+2 -6
hosts/weird-row-server/agnos.nix
··· 1 1 { 2 2 config, 3 + globals, 3 4 ... 4 5 }: 5 6 ··· 11 12 tcp = false; # let agnos manage the firewall 12 13 }; 13 14 14 - # disable dns stub listener or agnos cannot bind 15 - services.resolved.extraConfig = '' 16 - DNSStubListener=no 17 - ''; 18 - 19 15 age.secrets.agnos-account-key = { 20 16 file = secrets/agnos-account-key.age; 21 17 owner = config.security.agnos.user; ··· 24 20 enable = true; 25 21 temporarilyOpenFirewall = true; 26 22 settings = { 27 - dns_listen_addr = "0.0.0.0:53"; 23 + dns_listen_addr = "${globals.hosts.weird-row-server.ip}:53"; 28 24 29 25 accounts = [ 30 26 {
+3 -5
hosts/weird-row-server/authelia.nix
··· 181 181 } 182 182 ]; 183 183 184 - services.caddy = { 185 - virtualHosts.${globals.domains.authelia}.extraConfig = '' 186 - reverse_proxy http://localhost:${config.local.ports.authelia.string} 187 - ''; 188 - }; 184 + services.caddy.virtualHosts.${globals.domains.authelia}.extraConfig = '' 185 + reverse_proxy http://localhost:${config.local.ports.authelia.string} 186 + ''; 189 187 }; 190 188 }
+10 -12
hosts/weird-row-server/default.nix
··· 1 1 { 2 2 self, 3 + globals, 3 4 ... 4 5 }: 5 6 ··· 7 8 inherit (self.inputs) srvos; 8 9 9 10 ext-if = "eth0"; 10 - external-ip = "91.99.55.74"; 11 - external-netmask = 27; 12 - external-gw = "144.x.x.255"; 13 - external-ip6 = "2a01:4f8:c2c:76d2::1"; 14 - external-netmask6 = 64; 15 - external-gw6 = "fe80::1"; 11 + external-gateway = "144.x.x.255"; 12 + external-gateway6 = "fe80::1"; 16 13 in 17 14 { 18 15 imports = [ ··· 23 20 ./agnos.nix 24 21 ./authelia.nix 25 22 ./caddy.nix 23 + ./gatus.nix 26 24 ./goatcounter.nix 27 25 ./grafana.nix 28 26 ./headscale.nix ··· 67 65 interfaces.${ext-if} = { 68 66 ipv4.addresses = [ 69 67 { 70 - address = external-ip; 71 - prefixLength = external-netmask; 68 + address = globals.hosts.weird-row-server.ip; 69 + prefixLength = globals.hosts.weird-row-server.ip-prefix-length; 72 70 } 73 71 ]; 74 72 ipv6.addresses = [ 75 73 { 76 - address = external-ip6; 77 - prefixLength = external-netmask6; 74 + address = globals.hosts.weird-row-server.ip6; 75 + prefixLength = globals.hosts.weird-row-server.ip6-prefix-length; 78 76 } 79 77 ]; 80 78 }; 81 79 defaultGateway = { 82 80 interface = ext-if; 83 - address = external-gw; 81 + address = external-gateway; 84 82 }; 85 83 defaultGateway6 = { 86 84 interface = ext-if; 87 - address = external-gw6; 85 + address = external-gateway6; 88 86 }; 89 87 }; 90 88
+112
hosts/weird-row-server/gatus.nix
··· 1 + { 2 + config, 3 + globals, 4 + ... 5 + }: 6 + 7 + { 8 + config = { 9 + local.ports.gatus = 3018; 10 + 11 + age.secrets.gatus-env.file = secrets/gatus-env.age; 12 + 13 + services.gatus = { 14 + enable = true; 15 + environmentFile = config.age.secrets.gatus-env.path; 16 + 17 + settings = { 18 + web.port = config.local.ports.gatus.number; 19 + ui = { 20 + title = "Wiro's World Status"; 21 + header = "Wiro's World Status"; 22 + }; 23 + 24 + storage = { 25 + type = "sqlite"; 26 + path = "/var/lib/gatus/data.db"; 27 + }; 28 + connectivity.checker = { 29 + target = "1.1.1.1:53"; 30 + interval = "60s"; 31 + }; 32 + alerting.email = { 33 + from = "gatus@services.wiro.world"; 34 + 35 + username = "resend"; 36 + password = "$SMTP_PASSWORD"; 37 + host = "smtp.resend.com"; 38 + port = 2587; 39 + to = "milo@wiro.world"; 40 + 41 + default-alert = { 42 + description = "health check failed"; 43 + send-on-resolved = true; 44 + failure-threshold = 3; 45 + success-threshold = 2; 46 + }; 47 + }; 48 + 49 + endpoints = 50 + let 51 + groups = { 52 + public = "Public"; 53 + auth = "Authenticated"; 54 + net = "Net"; 55 + }; 56 + 57 + tests = { 58 + status200 = "[STATUS] == 200"; 59 + time300 = "[RESPONSE_TIME] < 300"; 60 + }; 61 + 62 + mkHttp = 63 + name: group: url: 64 + { 65 + interval ? "5m", 66 + conditions ? [ 67 + tests.status200 68 + tests.time300 69 + ], 70 + alerts ? [ 71 + { type = "email"; } 72 + ], 73 + }: 74 + { 75 + inherit 76 + name 77 + url 78 + group 79 + interval 80 + conditions 81 + alerts 82 + ; 83 + }; 84 + in 85 + [ 86 + (mkHttp "Website" groups.public "https://${globals.domains.website}/" { }) 87 + (mkHttp "Hypixel Bank Tracker" groups.public "https://${globals.domains.hbt-main}/" { }) 88 + (mkHttp "Hypixel Bank Tracker Banana" groups.public "https://${globals.domains.hbt-banana}/" { }) 89 + (mkHttp "Status" groups.public "https://${globals.domains.status}/" { }) 90 + # ensure we are reachable ourselves 91 + (mkHttp "Status'" groups.public "https://${globals.domains.status'}/" { }) 92 + 93 + (mkHttp "Miniflux" groups.auth "https://${globals.domains.miniflux}/" { }) 94 + (mkHttp "Vaultwarden" groups.auth "https://${globals.domains.vaultwarden}/" { }) 95 + (mkHttp "Headscale" groups.auth "https://${globals.domains.headscale}/health" { }) 96 + (mkHttp "Atproto PDS" groups.auth "https://${globals.domains.pds}/xrpc/_health" { }) 97 + (mkHttp "Goat Counter" groups.auth "https://${globals.domains.goatcounter}/" { }) 98 + 99 + (mkHttp "Warrior" groups.net "https://${globals.domains.warrior}/" { 100 + interval = "10m"; 101 + conditions = [ tests.status200 ]; 102 + }) 103 + (mkHttp "Grafana" groups.net "https://${globals.domains.grafana}/" { }) 104 + ]; 105 + }; 106 + }; 107 + 108 + services.caddy.virtualHosts.${globals.domains.status'}.extraConfig = '' 109 + reverse_proxy http://localhost:${toString config.services.gatus.settings.web.port} 110 + ''; 111 + }; 112 + }
+8 -10
hosts/weird-row-server/git-pages.nix
··· 26 26 }; 27 27 }; 28 28 29 - services.caddy = { 30 - virtualHosts.${globals.domains.pages} = { 31 - serverAliases = [ "test.wiro.world" ]; 32 - extraConfig = '' 33 - # TODO: enforce some kind of authentication for publishing websites 34 - # @write_ops { not method GET HEAD } 35 - # basicauth @write_ops { } 29 + services.caddy.virtualHosts.${globals.domains.pages} = { 30 + serverAliases = [ "test.wiro.world" ]; 31 + extraConfig = '' 32 + # TODO: enforce some kind of authentication for publishing websites 33 + # @write_ops { not method GET HEAD } 34 + # basicauth @write_ops { } 36 35 37 - reverse_proxy http://localhost:${config.local.ports.git-pages.string} 38 - ''; 39 - }; 36 + reverse_proxy http://localhost:${config.local.ports.git-pages.string} 37 + ''; 40 38 }; 41 39 }; 42 40 }
+4 -5
hosts/weird-row-server/goatcounter.nix
··· 13 13 14 14 port = config.local.ports.goatcounter.number; 15 15 proxy = true; 16 + # TODO: use caddy log instead js script to get visit information 16 17 extraArgs = [ "-automigrate" ]; 17 18 }; 18 19 19 - services.caddy = { 20 - virtualHosts.${globals.domains.goatcounter}.extraConfig = '' 21 - reverse_proxy http://localhost:${toString config.services.goatcounter.port} 22 - ''; 23 - }; 20 + services.caddy.virtualHosts.${globals.domains.goatcounter}.extraConfig = '' 21 + reverse_proxy http://localhost:${toString config.services.goatcounter.port} 22 + ''; 24 23 }; 25 24 }
+3 -5
hosts/weird-row-server/headscale.nix
··· 105 105 } 106 106 ]; 107 107 108 - services.caddy = { 109 - virtualHosts.${globals.domains.headscale}.extraConfig = '' 110 - reverse_proxy http://localhost:${config.local.ports.headscale.string} 111 - ''; 112 - }; 108 + services.caddy.virtualHosts.${globals.domains.headscale}.extraConfig = '' 109 + reverse_proxy http://localhost:${config.local.ports.headscale.string} 110 + ''; 113 111 }; 114 112 }
+5 -7
hosts/weird-row-server/lldap.nix
··· 36 36 environmentFile = config.age.secrets.lldap-env.path; 37 37 }; 38 38 39 - services.caddy = { 40 - virtualHosts.${globals.domains.lldap}.extraConfig = '' 41 - bind tailscale/ldap 42 - tls /var/lib/agnos/net.wiro.world_fullchain.pem /var/lib/agnos/net.wiro.world_privkey.pem 43 - reverse_proxy http://localhost:${toString config.services.lldap.settings.http_port} 44 - ''; 45 - }; 39 + services.caddy.virtualHosts.${globals.domains.lldap}.extraConfig = '' 40 + bind tailscale/ldap 41 + tls /var/lib/agnos/net.wiro.world_fullchain.pem /var/lib/agnos/net.wiro.world_privkey.pem 42 + reverse_proxy http://localhost:${toString config.services.lldap.settings.http_port} 43 + ''; 46 44 }; 47 45 }
+3 -5
hosts/weird-row-server/miniflux.nix
··· 51 51 } 52 52 ]; 53 53 54 - services.caddy = { 55 - virtualHosts.${globals.domains.miniflux}.extraConfig = '' 56 - reverse_proxy http://localhost:${config.local.ports.miniflux.string} 57 - ''; 58 - }; 54 + services.caddy.virtualHosts.${globals.domains.miniflux}.extraConfig = '' 55 + reverse_proxy http://localhost:${config.local.ports.miniflux.string} 56 + ''; 59 57 }; 60 58 }
+6 -8
hosts/weird-row-server/pds.nix
··· 24 24 ]; 25 25 }; 26 26 27 - services.caddy = { 28 - virtualHosts.${globals.domains.pds} = { 29 - serverAliases = [ "*.${globals.domains.pds}" ]; 30 - extraConfig = '' 31 - tls /var/lib/agnos/pds.wiro.world_fullchain.pem /var/lib/agnos/pds.wiro.world_privkey.pem 32 - reverse_proxy http://localhost:${toString config.services.bluesky-pds.settings.PDS_PORT} 33 - ''; 34 - }; 27 + services.caddy.virtualHosts.${globals.domains.pds} = { 28 + serverAliases = [ "*.${globals.domains.pds}" ]; 29 + extraConfig = '' 30 + tls /var/lib/agnos/pds.wiro.world_fullchain.pem /var/lib/agnos/pds.wiro.world_privkey.pem 31 + reverse_proxy http://localhost:${toString config.services.bluesky-pds.settings.PDS_PORT} 32 + ''; 35 33 }; 36 34 }; 37 35 }
+5 -3
hosts/weird-row-server/secrets/default.nix
··· 5 5 in 6 6 { 7 7 "agnos-account-key.age".publicKeys = deploy; 8 - # Defines `TS_AUTHKEY`, `HETZNER_API_TOKEN` 9 - "caddy-env.age".publicKeys = deploy; 10 8 "authelia-issuer-private-key.age".publicKeys = deploy; 11 9 "authelia-jwt-secret.age".publicKeys = deploy; 12 10 "authelia-ldap-password.age".publicKeys = deploy; 13 11 "authelia-smtp-password.age".publicKeys = deploy; 14 12 "authelia-storage-key.age".publicKeys = deploy; 13 + # Defines `TS_AUTHKEY`, `HETZNER_API_TOKEN` 14 + "caddy-env.age".publicKeys = deploy; 15 + # Defines `SMTP_PASSWORD` 16 + "gatus-env.age".publicKeys = deploy; 15 17 "grafana-oidc-secret.age".publicKeys = deploy; 16 18 "grafana-smtp-password.age".publicKeys = deploy; 17 19 "headscale-oidc-secret.age".publicKeys = deploy; ··· 22 24 "lldap-env.age".publicKeys = deploy; 23 25 "lldap-user-pass.age".publicKeys = deploy; 24 26 "miniflux-oidc-secret.age".publicKeys = deploy; 25 - # Defines `PDS_JWT_SECRET`, `PDS_ADMIN_PASSWORD`, `PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX`, `PDS_EMAIL_SMTP_URL`, `PDS_EMAIL_FROM_ADDRESS`. 27 + # Defines `PDS_JWT_SECRET`, `PDS_ADMIN_PASSWORD`, `PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX`, `PDS_EMAIL_SMTP_URL`, `PDS_EMAIL_FROM_ADDRESS` 26 28 "pds-env.age".publicKeys = deploy; 27 29 "tuwunel-registration-tokens.age".publicKeys = deploy; 28 30 # Defines `SMTP_PASSWORD`
hosts/weird-row-server/secrets/gatus-env.age

This is a binary file and will not be displayed.

+5 -7
hosts/weird-row-server/thelounge.nix
··· 21 21 }; 22 22 }; 23 23 24 - services.caddy = { 25 - virtualHosts.${globals.domains.thelounge}.extraConfig = '' 26 - bind tailscale/irc 27 - tls /var/lib/agnos/net.wiro.world_fullchain.pem /var/lib/agnos/net.wiro.world_privkey.pem 28 - reverse_proxy http://localhost:${toString config.services.thelounge.port} 29 - ''; 30 - }; 24 + services.caddy.virtualHosts.${globals.domains.thelounge}.extraConfig = '' 25 + bind tailscale/irc 26 + tls /var/lib/agnos/net.wiro.world_fullchain.pem /var/lib/agnos/net.wiro.world_privkey.pem 27 + reverse_proxy http://localhost:${toString config.services.thelounge.port} 28 + ''; 31 29 }; 32 30 }
+3 -5
hosts/weird-row-server/vaultwarden.nix
··· 29 29 }; 30 30 }; 31 31 32 - services.caddy = { 33 - virtualHosts.${globals.domains.vaultwarden}.extraConfig = '' 34 - reverse_proxy http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT} 35 - ''; 36 - }; 32 + services.caddy.virtualHosts.${globals.domains.vaultwarden}.extraConfig = '' 33 + reverse_proxy http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT} 34 + ''; 37 35 }; 38 36 }
+5 -7
hosts/weird-row-server/warrior.nix
··· 20 20 }; 21 21 }; 22 22 23 - services.caddy = { 24 - virtualHosts.${globals.domains.warrior}.extraConfig = '' 25 - bind tailscale/warrior 26 - tls /var/lib/agnos/net.wiro.world_fullchain.pem /var/lib/agnos/net.wiro.world_privkey.pem 27 - reverse_proxy http://localhost:${config.local.ports.warrior.string} 28 - ''; 29 - }; 23 + services.caddy.virtualHosts.${globals.domains.warrior}.extraConfig = '' 24 + bind tailscale/warrior 25 + tls /var/lib/agnos/net.wiro.world_fullchain.pem /var/lib/agnos/net.wiro.world_privkey.pem 26 + reverse_proxy http://localhost:${config.local.ports.warrior.string} 27 + ''; 30 28 }; 31 29 }
+31 -33
hosts/weird-row-server/webfinger.nix
··· 37 37 in 38 38 { 39 39 config = { 40 - services.caddy = { 41 - virtualHosts.${globals.domains.website}.extraConfig = '' 42 - @webfinger { 43 - path /.well-known/webfinger 44 - method GET HEAD 45 - query resource=acct:milo@wiro.world 46 - query resource=mailto:milo@wiro.world 47 - query resource=https://wiro.world 48 - query resource=https://wiro.world/ 49 - } 50 - route @webfinger { 51 - header { 52 - Content-Type "application/jrd+json" 53 - Access-Control-Allow-Origin "*" 54 - X-Robots-Tag "noindex" 55 - } 56 - root ${webfinger-dir} 57 - file_server 58 - } 59 - '' 60 - + '' 61 - @discord { 62 - path /.well-known/discord 63 - method GET HEAD 40 + services.caddy.virtualHosts.${globals.domains.website}.extraConfig = '' 41 + @webfinger { 42 + path /.well-known/webfinger 43 + method GET HEAD 44 + query resource=acct:milo@wiro.world 45 + query resource=mailto:milo@wiro.world 46 + query resource=https://wiro.world 47 + query resource=https://wiro.world/ 48 + } 49 + route @webfinger { 50 + header { 51 + Content-Type "application/jrd+json" 52 + Access-Control-Allow-Origin "*" 53 + X-Robots-Tag "noindex" 64 54 } 65 - route @discord { 66 - header { 67 - Access-Control-Allow-Origin "*" 68 - X-Robots-Tag "noindex" 69 - } 70 - root ${well-known-discord-dir} 71 - file_server 55 + root ${webfinger-dir} 56 + file_server 57 + } 58 + '' 59 + + '' 60 + @discord { 61 + path /.well-known/discord 62 + method GET HEAD 63 + } 64 + route @discord { 65 + header { 66 + Access-Control-Allow-Origin "*" 67 + X-Robots-Tag "noindex" 72 68 } 73 - ''; 74 - }; 69 + root ${well-known-discord-dir} 70 + file_server 71 + } 72 + ''; 75 73 }; 76 74 }