From 1ae463e796fba073d89e024504a40b04e825cf25 Mon Sep 17 00:00:00 2001 From: Shun Ueda Date: Sun, 7 Jun 2026 19:52:40 -0400 Subject: [PATCH 1/2] feat: vanity domains --- nix/treefmt.nix | 1 + .../oyasai-cdktf/src/stacks/common-infra.ts | 3 +- .../oyasai-cdktf/src/stacks/platform-infra.ts | 18 ++- .../src/stacks/platform-services.ts | 19 +++ .../_sources/generated.json | 136 ++++++++++-------- .../_sources/generated.nix | 20 ++- .../oyasai-standalone-images/nvfetcher.toml | 6 + packages/oyasai-standalone-images/package.nix | 18 ++- 8 files changed, 151 insertions(+), 70 deletions(-) diff --git a/nix/treefmt.nix b/nix/treefmt.nix index 0c38c2fae..533875001 100644 --- a/nix/treefmt.nix +++ b/nix/treefmt.nix @@ -64,5 +64,6 @@ settings.global.excludes = [ "*/gen/*" "docs/*" + "*/generated.*" ]; } diff --git a/packages/oyasai-cdktf/src/stacks/common-infra.ts b/packages/oyasai-cdktf/src/stacks/common-infra.ts index 62a208345..6b6f3e613 100644 --- a/packages/oyasai-cdktf/src/stacks/common-infra.ts +++ b/packages/oyasai-cdktf/src/stacks/common-infra.ts @@ -82,8 +82,7 @@ export class CommonInfra extends OyasaiTerraformStack { const secrets = createSecrets(this, this); - // TODO: Data because Cloudflare doesn't support importing registrar domain - // - shun 2026-04 + // "Data" because Cloudflare doesn't support importing this resource this.oyasaiIoRegistrarDomain = new DataCloudflareRegistrarDomain( this, this.t("oyasai-io-registrar-domain"), diff --git a/packages/oyasai-cdktf/src/stacks/platform-infra.ts b/packages/oyasai-cdktf/src/stacks/platform-infra.ts index 9b07b98a9..bdaec7070 100644 --- a/packages/oyasai-cdktf/src/stacks/platform-infra.ts +++ b/packages/oyasai-cdktf/src/stacks/platform-infra.ts @@ -15,6 +15,7 @@ export class PlatformInfra extends OyasaiPlatformTerraformStack { public readonly ipv4 = "121.81.157.109"; public readonly r2Bucket: R2Bucket; + public readonly rootDnsRecord: DnsRecord; public constructor( scope: Construct, @@ -41,19 +42,26 @@ export class PlatformInfra extends OyasaiPlatformTerraformStack { location: this.isMaster ? "apac" : "enam", }); + this.rootDnsRecord = new DnsRecord(this, this.t("root-dns-record"), { + ttl: 1, // automatic + zoneId: oyasaiIoZone.id, + name: `${this.environment}.${oyasaiIoRegistrarDomain.domainName}`, + type: "A", + proxied: false, + content: this.isMaster ? this.ipv4 : "0.0.0.0", + }); + + // Vanity domains if (this.isMaster) { - // We _can_ make dns record for every environment, though it's currently - // unnecessary. - shun 2026-04 - new DnsRecord(this, this.t("root-dns-record"), { + new DnsRecord(this, "root-vanity-dns-record", { ttl: 1, // automatic zoneId: oyasaiIoZone.id, name: oyasaiIoRegistrarDomain.domainName, type: "A", proxied: false, - content: this.ipv4, + content: this.rootDnsRecord.content, }); - // Proxy to our seesaawiki. Implicitly reserves `wiki.oyasai.io`. new DnsRecord(this, "seesaawiki-cname-dns-record", { ttl: 1, // automatic zoneId: oyasaiIoZone.id, diff --git a/packages/oyasai-cdktf/src/stacks/platform-services.ts b/packages/oyasai-cdktf/src/stacks/platform-services.ts index d11613fb8..2e271719e 100644 --- a/packages/oyasai-cdktf/src/stacks/platform-services.ts +++ b/packages/oyasai-cdktf/src/stacks/platform-services.ts @@ -50,6 +50,7 @@ export class PlatformServices extends OyasaiPlatformTerraformStack { const imageIds = JSON.parse(process.env.OYASAI_IMAGE_ID as string); const images = { // keep-sorted start + caddy: imageIds["caddy"], mariadb: imageIds.mariadb, minecraftAxiom: imageIds["oyasai-minecraft-axiom"], minecraftBackup: imageIds["mc-backup"], @@ -289,6 +290,24 @@ export class PlatformServices extends OyasaiPlatformTerraformStack { DB_DEBUG: true, }), }); + + new Container(this, this.t("caddy-container"), { + image: images.caddy, + name: "caddy", + restart: "unless-stopped", + networksAdvanced: [network], + ports: ports({ + tcp: [443], + }), + command: [ + "reverse-proxy", + "--from", + platformInfra.rootDnsRecord.name, + "--to", + // TODO: replace with actual + "example.com", + ], + }); } } } diff --git a/packages/oyasai-standalone-images/_sources/generated.json b/packages/oyasai-standalone-images/_sources/generated.json index caacc7f2d..f51e69e04 100644 --- a/packages/oyasai-standalone-images/_sources/generated.json +++ b/packages/oyasai-standalone-images/_sources/generated.json @@ -1,62 +1,82 @@ { - "mariadb": { - "cargoLock": null, - "date": null, - "extract": null, - "name": "mariadb", - "passthru": null, - "pinned": false, - "src": { - "arch": "amd64", - "finalImageName": null, - "finalImageTag": null, - "imageDigest": "sha256:d8369cb7020907b44ab0a7a73f855e41cbd5b6da16e01fbd8b8fe21200c7a854", - "imageName": "mariadb", - "imageTag": "10.4.28", - "os": "linux", - "sha256": "sha256-pIEYzawoBIJI295R0ToQyueVVDGLfYItnn8mySwhvLs=", - "tlsVerify": null + "caddy": { + "cargoLock": null, + "date": null, + "extract": null, + "name": "caddy", + "passthru": null, + "pinned": false, + "src": { + "arch": "amd64", + "finalImageName": null, + "finalImageTag": null, + "imageDigest": "sha256:ec18ee54aab3315c22e25f3b2babda73ff8007d39b13b3bd1bfffa2f0444c7d9", + "imageName": "caddy", + "imageTag": "2.11.3", + "os": "linux", + "sha256": "sha256-e7XCeWxwkjZKxLBOjc23j80pngi8jQZJ2kSfs7A9TaY=", + "tlsVerify": null + }, + "version": "2.11.3" }, - "version": "10.4.28" - }, - "mc-backup": { - "cargoLock": null, - "date": null, - "extract": null, - "name": "mc-backup", - "passthru": null, - "pinned": false, - "src": { - "arch": "amd64", - "finalImageName": null, - "finalImageTag": null, - "imageDigest": "sha256:3ee78d8c49d70efc4dfc06d362051b5a028d4f28f2f0fe095e3cbccd29ab511d", - "imageName": "itzg/mc-backup", - "imageTag": "2026.5.0", - "os": "linux", - "sha256": "sha256-VbYN9VF/9LJPXhH5HSISQ+3YzqJlliUtiE39oWFPcBw=", - "tlsVerify": null + "mariadb": { + "cargoLock": null, + "date": null, + "extract": null, + "name": "mariadb", + "passthru": null, + "pinned": false, + "src": { + "arch": "amd64", + "finalImageName": null, + "finalImageTag": null, + "imageDigest": "sha256:d8369cb7020907b44ab0a7a73f855e41cbd5b6da16e01fbd8b8fe21200c7a854", + "imageName": "mariadb", + "imageTag": "10.4.28", + "os": "linux", + "sha256": "sha256-pIEYzawoBIJI295R0ToQyueVVDGLfYItnn8mySwhvLs=", + "tlsVerify": null + }, + "version": "10.4.28" }, - "version": "2026.5.0" - }, - "mysql-backup": { - "cargoLock": null, - "date": null, - "extract": null, - "name": "mysql-backup", - "passthru": null, - "pinned": false, - "src": { - "arch": "amd64", - "finalImageName": null, - "finalImageTag": null, - "imageDigest": "sha256:9a9a12dc942c370040ced1d43ab9f7d1162e9fde7f38b0f7749c3516d79a812c", - "imageName": "databack/mysql-backup", - "imageTag": "1.4.0", - "os": "linux", - "sha256": "sha256-6I4SlD+N7jzTDqH7hfu6C7Sh4ALaL6WpkWqTjrhoCK0=", - "tlsVerify": null + "mc-backup": { + "cargoLock": null, + "date": null, + "extract": null, + "name": "mc-backup", + "passthru": null, + "pinned": false, + "src": { + "arch": "amd64", + "finalImageName": null, + "finalImageTag": null, + "imageDigest": "sha256:f4f2b46f4cd67c74ba65ea3c2a4effb19804e834e84a64c071a4f3a47ebd6b44", + "imageName": "itzg/mc-backup", + "imageTag": "2026.6.0", + "os": "linux", + "sha256": "sha256-AqUbsoGMSb9SebWLrzWcjWMhYrC6COVcUIikjjUGG2Q=", + "tlsVerify": null + }, + "version": "2026.6.0" }, - "version": "1.4.0" - } -} + "mysql-backup": { + "cargoLock": null, + "date": null, + "extract": null, + "name": "mysql-backup", + "passthru": null, + "pinned": false, + "src": { + "arch": "amd64", + "finalImageName": null, + "finalImageTag": null, + "imageDigest": "sha256:9a9a12dc942c370040ced1d43ab9f7d1162e9fde7f38b0f7749c3516d79a812c", + "imageName": "databack/mysql-backup", + "imageTag": "1.4.0", + "os": "linux", + "sha256": "sha256-6I4SlD+N7jzTDqH7hfu6C7Sh4ALaL6WpkWqTjrhoCK0=", + "tlsVerify": null + }, + "version": "1.4.0" + } +} \ No newline at end of file diff --git a/packages/oyasai-standalone-images/_sources/generated.nix b/packages/oyasai-standalone-images/_sources/generated.nix index 1d2418e09..411eaacb5 100644 --- a/packages/oyasai-standalone-images/_sources/generated.nix +++ b/packages/oyasai-standalone-images/_sources/generated.nix @@ -6,6 +6,18 @@ dockerTools, }: { + caddy = { + pname = "caddy"; + version = "2.11.3"; + src = dockerTools.pullImage { + imageName = "caddy"; + imageDigest = "sha256:ec18ee54aab3315c22e25f3b2babda73ff8007d39b13b3bd1bfffa2f0444c7d9"; + sha256 = "sha256-e7XCeWxwkjZKxLBOjc23j80pngi8jQZJ2kSfs7A9TaY="; + finalImageTag = "2.11.3"; + os = "linux"; + arch = "amd64"; + }; + }; mariadb = { pname = "mariadb"; version = "10.4.28"; @@ -20,12 +32,12 @@ }; mc-backup = { pname = "mc-backup"; - version = "2026.5.0"; + version = "2026.6.0"; src = dockerTools.pullImage { imageName = "itzg/mc-backup"; - imageDigest = "sha256:3ee78d8c49d70efc4dfc06d362051b5a028d4f28f2f0fe095e3cbccd29ab511d"; - sha256 = "sha256-VbYN9VF/9LJPXhH5HSISQ+3YzqJlliUtiE39oWFPcBw="; - finalImageTag = "2026.5.0"; + imageDigest = "sha256:f4f2b46f4cd67c74ba65ea3c2a4effb19804e834e84a64c071a4f3a47ebd6b44"; + sha256 = "sha256-AqUbsoGMSb9SebWLrzWcjWMhYrC6COVcUIikjjUGG2Q="; + finalImageTag = "2026.6.0"; os = "linux"; arch = "amd64"; }; diff --git a/packages/oyasai-standalone-images/nvfetcher.toml b/packages/oyasai-standalone-images/nvfetcher.toml index fc1705e93..f51663a73 100644 --- a/packages/oyasai-standalone-images/nvfetcher.toml +++ b/packages/oyasai-standalone-images/nvfetcher.toml @@ -1,3 +1,9 @@ +[caddy] +docker.os = "linux" +docker.arch = "amd64" +fetch.docker = "caddy" +src.manual = "2.11.3" + [mariadb] docker.os = "linux" docker.arch = "amd64" diff --git a/packages/oyasai-standalone-images/package.nix b/packages/oyasai-standalone-images/package.nix index 2c2548c72..c110121d2 100644 --- a/packages/oyasai-standalone-images/package.nix +++ b/packages/oyasai-standalone-images/package.nix @@ -5,11 +5,26 @@ }: let - inherit (callPackage ./_sources/generated.nix { }) mariadb mc-backup mysql-backup; + inherit (callPackage ./_sources/generated.nix { }) + # keep-sorted start + caddy + mariadb + mc-backup + mysql-backup + # keep-sorted end + ; in runCommandLocal "oyasai-standalone-images" { passthru = { + # keep-sorted start block=yes + caddy = oyasaiDockerTools.buildImage { + name = caddy.pname; + fromImage = caddy.src; + config = { + Entrypoint = [ "caddy" ]; + }; + }; mariadb = oyasaiDockerTools.buildImage { name = mariadb.pname; fromImage = mariadb.src; @@ -33,6 +48,7 @@ runCommandLocal "oyasai-standalone-images" Entrypoint = [ "/entrypoint" ]; }; }; + # keep-sorted end }; } '' From 12178b1a919829074eff0937054c6cb307d69d92 Mon Sep 17 00:00:00 2001 From: Shun Ueda Date: Tue, 9 Jun 2026 11:33:01 -0400 Subject: [PATCH 2/2] fix: use traefik --- .../src/stacks/platform-services.ts | 79 ++++++++++++++++--- .../_sources/generated.json | 40 +++++----- .../_sources/generated.nix | 24 +++--- .../oyasai-standalone-images/nvfetcher.toml | 12 +-- packages/oyasai-standalone-images/package.nix | 17 ++-- 5 files changed, 115 insertions(+), 57 deletions(-) diff --git a/packages/oyasai-cdktf/src/stacks/platform-services.ts b/packages/oyasai-cdktf/src/stacks/platform-services.ts index 2e271719e..aebd798c5 100644 --- a/packages/oyasai-cdktf/src/stacks/platform-services.ts +++ b/packages/oyasai-cdktf/src/stacks/platform-services.ts @@ -50,13 +50,13 @@ export class PlatformServices extends OyasaiPlatformTerraformStack { const imageIds = JSON.parse(process.env.OYASAI_IMAGE_ID as string); const images = { // keep-sorted start - caddy: imageIds["caddy"], mariadb: imageIds.mariadb, minecraftAxiom: imageIds["oyasai-minecraft-axiom"], minecraftBackup: imageIds["mc-backup"], minecraftLobby: imageIds["oyasai-minecraft-lobby"], minecraftMain: imageIds["oyasai-minecraft-main"], mysqlBackup: imageIds["mysql-backup"], + traefik: imageIds["traefik"], velocity: imageIds["oyasai-velocity"], // keep-sorted end } as const; @@ -68,6 +68,7 @@ export class PlatformServices extends OyasaiPlatformTerraformStack { minecraftAxiom: join(baseHostPath, "minecraft-axiom"), minecraftLobby: join(baseHostPath, "minecraft-lobby"), minecraftMain: join(baseHostPath, "minecraft-main"), + traefik: join(baseHostPath, "traefik"), velocity: join(baseHostPath, "velocity"), // keep-sorted end } as const; @@ -135,6 +136,25 @@ export class PlatformServices extends OyasaiPlatformTerraformStack { hostPath: hostPaths.minecraftMain, }, ], + labels: [ + { label: "traefik.enable", value: "true" }, + { + label: "traefik.http.routers.bluemap.rule", + value: `Host(\`bluemap.${platformInfra.rootDnsRecord.name}\`)`, + }, + { + label: "traefik.http.routers.bluemap.entrypoints", + value: "websecure", + }, + { + label: "traefik.http.routers.bluemap.tls.certresolver", + value: "myresolver", + }, + { + label: "traefik.http.services.bluemap.loadbalancer.server.port", + value: "8100", + }, + ], ...(this.isMaster && { // Pin container to P-cores only (logical CPUs 0–11) to avoid latency // spikes caused by the main tick thread being scheduled on E-cores. @@ -291,21 +311,58 @@ export class PlatformServices extends OyasaiPlatformTerraformStack { }), }); - new Container(this, this.t("caddy-container"), { - image: images.caddy, - name: "caddy", + new Container(this, this.t("traefik-container"), { + image: images.traefik, + name: "traefik", restart: "unless-stopped", networksAdvanced: [network], ports: ports({ - tcp: [443], + tcp: [80, 443], }), command: [ - "reverse-proxy", - "--from", - platformInfra.rootDnsRecord.name, - "--to", - // TODO: replace with actual - "example.com", + "--providers.docker=true", + "--providers.docker.exposedbydefault=false", + "--entrypoints.web.address=:80", + "--entrypoints.websecure.address=:443", + "--entrypoints.web.http.redirections.entrypoint.to=websecure", + "--entrypoints.web.http.redirections.entrypoint.scheme=https", + "--certificatesresolvers.myresolver.acme.tlschallenge=true", + ], + volumes: [ + { + hostPath: "/var/run/docker.sock", + containerPath: "/var/run/docker.sock", + }, + { + hostPath: hostPaths.traefik, + containerPath: "/etc/traefik/acme", + }, + ], + }); + + new Container(this, this.t("hello-world-container"), { + image: "containous/whoami:latest", + name: "hello-world-web", + restart: "unless-stopped", + networksAdvanced: [network], + labels: [ + { label: "traefik.enable", value: "true" }, + { + label: "traefik.http.routers.helloworld.rule", + value: `Host(\`${platformInfra.rootDnsRecord.name}\`)`, + }, + { + label: "traefik.http.routers.helloworld.entrypoints", + value: "websecure", + }, + { + label: "traefik.http.routers.helloworld.tls.certresolver", + value: "myresolver", + }, + { + label: "traefik.http.services.helloworld.loadbalancer.server.port", + value: "80", + }, ], }); } diff --git a/packages/oyasai-standalone-images/_sources/generated.json b/packages/oyasai-standalone-images/_sources/generated.json index f51e69e04..4edd6fadb 100644 --- a/packages/oyasai-standalone-images/_sources/generated.json +++ b/packages/oyasai-standalone-images/_sources/generated.json @@ -1,24 +1,4 @@ { - "caddy": { - "cargoLock": null, - "date": null, - "extract": null, - "name": "caddy", - "passthru": null, - "pinned": false, - "src": { - "arch": "amd64", - "finalImageName": null, - "finalImageTag": null, - "imageDigest": "sha256:ec18ee54aab3315c22e25f3b2babda73ff8007d39b13b3bd1bfffa2f0444c7d9", - "imageName": "caddy", - "imageTag": "2.11.3", - "os": "linux", - "sha256": "sha256-e7XCeWxwkjZKxLBOjc23j80pngi8jQZJ2kSfs7A9TaY=", - "tlsVerify": null - }, - "version": "2.11.3" - }, "mariadb": { "cargoLock": null, "date": null, @@ -78,5 +58,25 @@ "tlsVerify": null }, "version": "1.4.0" + }, + "traefik": { + "cargoLock": null, + "date": null, + "extract": null, + "name": "traefik", + "passthru": null, + "pinned": false, + "src": { + "arch": "amd64", + "finalImageName": null, + "finalImageTag": null, + "imageDigest": "sha256:fcdef599e6259359833dd2e1d49f9e964f66825d69bd3dd468f51102ce013d03", + "imageName": "traefik", + "imageTag": "3.7.4", + "os": "linux", + "sha256": "sha256-R/XwyezYqVIK1+wm8DuDcdnCU4Z+qhfz8M9OWs64qFo=", + "tlsVerify": null + }, + "version": "3.7.4" } } \ No newline at end of file diff --git a/packages/oyasai-standalone-images/_sources/generated.nix b/packages/oyasai-standalone-images/_sources/generated.nix index 411eaacb5..50b910a62 100644 --- a/packages/oyasai-standalone-images/_sources/generated.nix +++ b/packages/oyasai-standalone-images/_sources/generated.nix @@ -6,18 +6,6 @@ dockerTools, }: { - caddy = { - pname = "caddy"; - version = "2.11.3"; - src = dockerTools.pullImage { - imageName = "caddy"; - imageDigest = "sha256:ec18ee54aab3315c22e25f3b2babda73ff8007d39b13b3bd1bfffa2f0444c7d9"; - sha256 = "sha256-e7XCeWxwkjZKxLBOjc23j80pngi8jQZJ2kSfs7A9TaY="; - finalImageTag = "2.11.3"; - os = "linux"; - arch = "amd64"; - }; - }; mariadb = { pname = "mariadb"; version = "10.4.28"; @@ -54,4 +42,16 @@ arch = "amd64"; }; }; + traefik = { + pname = "traefik"; + version = "3.7.4"; + src = dockerTools.pullImage { + imageName = "traefik"; + imageDigest = "sha256:fcdef599e6259359833dd2e1d49f9e964f66825d69bd3dd468f51102ce013d03"; + sha256 = "sha256-R/XwyezYqVIK1+wm8DuDcdnCU4Z+qhfz8M9OWs64qFo="; + finalImageTag = "3.7.4"; + os = "linux"; + arch = "amd64"; + }; + }; } diff --git a/packages/oyasai-standalone-images/nvfetcher.toml b/packages/oyasai-standalone-images/nvfetcher.toml index f51663a73..c709bd226 100644 --- a/packages/oyasai-standalone-images/nvfetcher.toml +++ b/packages/oyasai-standalone-images/nvfetcher.toml @@ -1,9 +1,3 @@ -[caddy] -docker.os = "linux" -docker.arch = "amd64" -fetch.docker = "caddy" -src.manual = "2.11.3" - [mariadb] docker.os = "linux" docker.arch = "amd64" @@ -21,3 +15,9 @@ docker.os = "linux" docker.arch = "amd64" fetch.docker = "databack/mysql-backup" src.manual = "1.4.0" + +[traefik] +docker.os = "linux" +docker.arch = "amd64" +fetch.docker = "traefik" +src.manual = "3.7.4" diff --git a/packages/oyasai-standalone-images/package.nix b/packages/oyasai-standalone-images/package.nix index c110121d2..d968ac6f2 100644 --- a/packages/oyasai-standalone-images/package.nix +++ b/packages/oyasai-standalone-images/package.nix @@ -7,10 +7,10 @@ let inherit (callPackage ./_sources/generated.nix { }) # keep-sorted start - caddy mariadb mc-backup mysql-backup + traefik # keep-sorted end ; in @@ -18,13 +18,6 @@ runCommandLocal "oyasai-standalone-images" { passthru = { # keep-sorted start block=yes - caddy = oyasaiDockerTools.buildImage { - name = caddy.pname; - fromImage = caddy.src; - config = { - Entrypoint = [ "caddy" ]; - }; - }; mariadb = oyasaiDockerTools.buildImage { name = mariadb.pname; fromImage = mariadb.src; @@ -48,6 +41,14 @@ runCommandLocal "oyasai-standalone-images" Entrypoint = [ "/entrypoint" ]; }; }; + traefik = oyasaiDockerTools.buildImage { + name = traefik.pname; + fromImage = traefik.src; + config = { + Entrypoint = [ "/entrypoint.sh" ]; + Cmd = [ "traefik" ]; + }; + }; # keep-sorted end }; }