change domains, ips and make flake check work
This commit is contained in:
@@ -13,7 +13,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
install -m 600 /dev/stdin ~/.ssh/id_ed25519 <<< "${{ secrets.DEPLOY_SSH_KEY }}"
|
install -m 600 /dev/stdin ~/.ssh/id_ed25519 <<< "${{ secrets.DEPLOY_SSH_KEY }}"
|
||||||
ssh-keyscan -H db-host.gebos.internal app-host.gebos.internal ingest.ge-bos.de >> ~/.ssh/known_hosts 2>/dev/null || true
|
ssh-keyscan -H db.gebos.online app.gebos.online ingest.gebos.online >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||||
|
|
||||||
- name: Build all closures
|
- name: Build all closures
|
||||||
run: nix flake check --no-build
|
run: nix flake check --no-build
|
||||||
|
|||||||
@@ -9,15 +9,28 @@ and CI/CD pipelines for the project. Everything is one `flake.nix`.
|
|||||||
|
|
||||||
Three hosts (see issue #21 for the full design discussion):
|
Three hosts (see issue #21 for the full design discussion):
|
||||||
|
|
||||||
| Host | Role | Public hostname |
|
| Host | Role | Public hostname | Private IP |
|
||||||
| ------------- | ----------------------------------------- | ---------------------- |
|
| ------------- | ----------------------------------------- | ---------------------- | ---------- |
|
||||||
| `mqtt-ingest` | HiveMQ CE + Go MQTT→Postgres ingester | `ingest.ge-bos.de` |
|
| `mqtt-ingest` | HiveMQ CE + Go MQTT→Postgres ingester | `ingest.gebos.online` | `10.0.0.4` |
|
||||||
| `db-host` | Postgres 17 + TimescaleDB (telemetry+auth)| internal only |
|
| `db-host` | Postgres 17 + TimescaleDB (telemetry+auth)| `db.gebos.online` (SSH only) | `10.0.0.2` |
|
||||||
| `app-host` | Caddy + Kong + Supabase (compose) + SPA | `app.ge-bos.de`, `api.ge-bos.de` |
|
| `app-host` | Caddy + Kong + Supabase (compose) + SPA | `app.gebos.online`, `api.gebos.online` | `10.0.0.3` |
|
||||||
|
|
||||||
Public REST surface is PostgREST + SQL `/rpc/` functions, fronted by Kong, TLS-terminated by Caddy.
|
Public REST surface is PostgREST + SQL `/rpc/` functions, fronted by Kong, TLS-terminated by Caddy.
|
||||||
Supabase Studio is bound to `127.0.0.1` on `app-host` — reach it with `ssh -L 3000:127.0.0.1:3000 app-host`.
|
Supabase Studio is bound to `127.0.0.1` on `app-host` — reach it with `ssh -L 3000:127.0.0.1:3000 app-host`.
|
||||||
|
|
||||||
|
### Networking
|
||||||
|
|
||||||
|
There is no private DNS. Each host has a public hostname (used for `deploy-rs`
|
||||||
|
SSH access from the Gitea runner, which is **not** on the private network, plus
|
||||||
|
TLS ingress where applicable), and a static `10.0.0.0/8` IP used for all
|
||||||
|
host-to-host traffic:
|
||||||
|
|
||||||
|
- `db.gebos.online` is for SSH/deploy only — Postgres is never exposed publicly.
|
||||||
|
- `app-host` and `mqtt-ingest` reach Postgres at `10.0.0.2:5432` over the private
|
||||||
|
network.
|
||||||
|
- `db-host` only accepts Postgres (port 5432) from `10.0.0.0/8` (firewall rule
|
||||||
|
in `nix/hosts/db-host.nix`).
|
||||||
|
|
||||||
## Repo layout
|
## Repo layout
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
{ buildNpmPackage, lib }:
|
{ buildNpmPackage }:
|
||||||
|
|
||||||
buildNpmPackage {
|
buildNpmPackage {
|
||||||
pname = "gebos-frontend";
|
pname = "gebos-frontend";
|
||||||
version = "0.0.0";
|
version = "0.0.0";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
# Filled in once package-lock.json exists.
|
npmDepsHash = "sha256-GeXgNbf94QRLNaZP8ma2vx19Vzm8jDWPeOTvE9exwm0=";
|
||||||
npmDepsHash = lib.fakeHash;
|
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
runHook preInstall
|
runHook preInstall
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const DEV_SUPABASE_ANON_KEY =
|
|||||||
|
|
||||||
const SUPABASE_URL =
|
const SUPABASE_URL =
|
||||||
import.meta.env.VITE_SUPABASE_URL ??
|
import.meta.env.VITE_SUPABASE_URL ??
|
||||||
(import.meta.env.DEV ? DEV_SUPABASE_URL : "https://api.ge-bos.de");
|
(import.meta.env.DEV ? DEV_SUPABASE_URL : "https://api.gebos.online");
|
||||||
|
|
||||||
const SUPABASE_ANON_KEY =
|
const SUPABASE_ANON_KEY =
|
||||||
import.meta.env.VITE_SUPABASE_ANON_KEY ??
|
import.meta.env.VITE_SUPABASE_ANON_KEY ??
|
||||||
|
|||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
+6
-3
@@ -18,8 +18,11 @@ in
|
|||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
# Order matters: the Gitea Actions workflow invokes them in this sequence.
|
# Order matters: the Gitea Actions workflow invokes them in this sequence.
|
||||||
db-host = mkNode "db-host" "db-host.gebos.internal"; # TODO: real address
|
# SSH/deploy targets use public hostnames because the Gitea runner is not on
|
||||||
app-host = mkNode "app-host" "app-host.gebos.internal"; # TODO: real address
|
# the private network. Host-to-host traffic still uses the 10.0.0.0/8 IPs.
|
||||||
mqtt-ingest = mkNode "mqtt-ingest" "ingest.ge-bos.de";
|
# See the host address table in README.md.
|
||||||
|
db-host = mkNode "db-host" "db.gebos.online";
|
||||||
|
app-host = mkNode "app-host" "app.gebos.online";
|
||||||
|
mqtt-ingest = mkNode "mqtt-ingest" "ingest.gebos.online";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ let
|
|||||||
VITE_SUPABASE_URL = dev.supabaseUrl;
|
VITE_SUPABASE_URL = dev.supabaseUrl;
|
||||||
VITE_SUPABASE_ANON_KEY = dev.anonKey;
|
VITE_SUPABASE_ANON_KEY = dev.anonKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# services-flake ships no MQTT broker, so run mosquitto as a plain
|
||||||
|
# process-compose process. Anonymous access on the dev listener only.
|
||||||
|
mosquittoConf = pkgs.writeText "mosquitto-dev.conf" ''
|
||||||
|
listener ${toString dev.mqttPort} ${dev.mqttHost}
|
||||||
|
allow_anonymous true
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ services-flake.processComposeModules.default ];
|
imports = [ services-flake.processComposeModules.default ];
|
||||||
@@ -48,14 +55,18 @@ in
|
|||||||
port = dev.pgPort;
|
port = dev.pgPort;
|
||||||
initialDatabases = [{ name = dev.pgDB; }];
|
initialDatabases = [{ name = dev.pgDB; }];
|
||||||
};
|
};
|
||||||
|
|
||||||
mosquitto."broker" = {
|
|
||||||
enable = true;
|
|
||||||
port = dev.mqttPort;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.processes = {
|
settings.processes = {
|
||||||
|
broker = {
|
||||||
|
command = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf}";
|
||||||
|
readiness_probe = {
|
||||||
|
exec.command = "${pkgs.mosquitto}/bin/mosquitto_sub -h ${dev.mqttHost} -p ${toString dev.mqttPort} -t '$$SYS/#' -C 1 -W 2";
|
||||||
|
initial_delay_seconds = 1;
|
||||||
|
period_seconds = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
ingester = {
|
ingester = {
|
||||||
command = "${pkgs.go}/bin/go run ./ingester";
|
command = "${pkgs.go}/bin/go run ./ingester";
|
||||||
environment = ingesterEnv;
|
environment = ingesterEnv;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
services.gebos.supabase = {
|
services.gebos.supabase = {
|
||||||
enable = true;
|
enable = true;
|
||||||
# Compose stack points at external db-host instead of the bundled `db` service.
|
# Compose stack points at external db-host instead of the bundled `db` service.
|
||||||
postgresHost = "db-host.gebos.internal"; # TODO: real internal hostname
|
postgresHost = "10.0.0.2"; # db-host on the private network
|
||||||
postgresPort = 5432;
|
postgresPort = 5432;
|
||||||
# Studio bound to loopback only — reach via `ssh -L 3000:127.0.0.1:3000 app-host`.
|
# Studio bound to loopback only — reach via `ssh -L 3000:127.0.0.1:3000 app-host`.
|
||||||
studioBindAddress = "127.0.0.1";
|
studioBindAddress = "127.0.0.1";
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
# Caddy terminates TLS, proxies to Kong on 127.0.0.1:8000.
|
# Caddy terminates TLS, proxies to Kong on 127.0.0.1:8000.
|
||||||
sites = {
|
sites = {
|
||||||
"api.ge-bos.de" = { upstream = "127.0.0.1:8000"; }; # → Kong → PostgREST/GoTrue
|
"api.gebos.online" = { upstream = "127.0.0.1:8000"; }; # → Kong → PostgREST/GoTrue
|
||||||
"app.ge-bos.de" = { staticRoot = "${config.services.gebos.frontend.package}/share/frontend"; };
|
"app.gebos.online" = { staticRoot = "${config.services.gebos.frontend.package}/share/frontend"; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
settings.PasswordAuthentication = false;
|
settings.PasswordAuthentication = false;
|
||||||
};
|
};
|
||||||
|
# TODO: restrict inbound SSH (port 22) to the Gitea deployment runner's IP
|
||||||
|
# only, instead of leaving it open to the world. Likely via
|
||||||
|
# services.openssh.openFirewall = false + a firewall.extraInputRules rule
|
||||||
|
# accepting tcp dport 22 from the runner's source address.
|
||||||
|
|
||||||
networking.firewall.enable = true;
|
networking.firewall.enable = true;
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,15 @@
|
|||||||
services.gebos.ingester = {
|
services.gebos.ingester = {
|
||||||
enable = true;
|
enable = true;
|
||||||
# mqttBroker defaults to tcp://127.0.0.1:1883 (the local HiveMQ).
|
# mqttBroker defaults to tcp://127.0.0.1:1883 (the local HiveMQ).
|
||||||
postgresUrl = "postgres://gebos_ingest@db-host.gebos.internal:5432/postgres?sslmode=require";
|
postgresUrl = "postgres://gebos_ingest@10.0.0.2:5432/postgres?sslmode=require";
|
||||||
# GEBOS_POSTGRES_PASSWORD sourced from /run/secrets/gebos-env (sops-nix).
|
# GEBOS_POSTGRES_PASSWORD sourced from /run/secrets/gebos-env (sops-nix).
|
||||||
};
|
};
|
||||||
|
|
||||||
# Caddy fronts TLS for `ingest.ge-bos.de` and forwards to HiveMQ.
|
# Caddy fronts TLS for `ingest.gebos.online` and forwards to HiveMQ.
|
||||||
services.gebos.caddy = {
|
services.gebos.caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
sites = {
|
sites = {
|
||||||
"ingest.ge-bos.de" = { tcpProxy = "127.0.0.1:8883"; };
|
"ingest.gebos.online" = { tcpProxy = "127.0.0.1:8883"; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.caddy = {
|
services.caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
email = "ops@ge-bos.de"; # TODO: confirm ACME contact
|
email = "ops@gebos.online"; # TODO: confirm ACME contact
|
||||||
extraConfig = lib.concatStringsSep "\n"
|
extraConfig = lib.concatStringsSep "\n"
|
||||||
(lib.mapAttrsToList siteBlock cfg.sites);
|
(lib.mapAttrsToList siteBlock cfg.sites);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ services:
|
|||||||
image: kong:2.8.1
|
image: kong:2.8.1
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8000:8000/tcp" # Caddy proxies api.ge-bos.de here
|
- "127.0.0.1:8000:8000/tcp" # Caddy proxies api.gebos.online here
|
||||||
environment:
|
environment:
|
||||||
KONG_DATABASE: "off"
|
KONG_DATABASE: "off"
|
||||||
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
|
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
|
||||||
@@ -29,10 +29,10 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
GOTRUE_DB_DRIVER: postgres
|
GOTRUE_DB_DRIVER: postgres
|
||||||
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
||||||
GOTRUE_SITE_URL: https://app.ge-bos.de
|
GOTRUE_SITE_URL: https://app.gebos.online
|
||||||
GOTRUE_JWT_SECRET: ${JWT_SECRET}
|
GOTRUE_JWT_SECRET: ${JWT_SECRET}
|
||||||
GOTRUE_JWT_EXP: "3600"
|
GOTRUE_JWT_EXP: "3600"
|
||||||
API_EXTERNAL_URL: https://api.ge-bos.de
|
API_EXTERNAL_URL: https://api.gebos.online
|
||||||
|
|
||||||
rest:
|
rest:
|
||||||
image: postgrest/postgrest:v12.0.2
|
image: postgrest/postgrest:v12.0.2
|
||||||
@@ -52,7 +52,7 @@ services:
|
|||||||
STUDIO_PG_META_URL: http://meta:8080
|
STUDIO_PG_META_URL: http://meta:8080
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
DEFAULT_ORGANIZATION_NAME: Gebos
|
DEFAULT_ORGANIZATION_NAME: Gebos
|
||||||
SUPABASE_URL: https://api.ge-bos.de
|
SUPABASE_URL: https://api.gebos.online
|
||||||
DASHBOARD_USERNAME: gebos
|
DASHBOARD_USERNAME: gebos
|
||||||
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
|
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user