# Tomter Vel's own platform: portal + its own Kanidm and NATS as podman # containers. The content (pages, forms, desks) is not here: portal fetches # it from tomtervel/questions on prosjekt.klingenbergbygg.no and hot-reloads # it over NATS. This repo owns identity, the bus, and which portal version # runs. TLS depends on where it runs: on a standalone host the bundled Caddy # (`--profile edge`) terminates it; on kasse the host Caddy already owns # 80/443 and reverse-proxies vel.klingenbergbygg.no -> portal (127.0.0.1:3050). # # bootstrap.sh first time on a fresh host: renders configs from # .env, makes Kanidm's internal cert, starts it all, # recovers the Kanidm admin, creates the portal client # and desk groups. # podman compose up -d --build every time after that. name: tomtervel services: caddy: # Bundled TLS for a standalone host only: `podman compose --profile edge up`. # On kasse the host Caddy already owns 80/443 (it reverse-proxies # vel.klingenbergbygg.no -> 127.0.0.1:3050, the portal port below), so this # is profiled off there to avoid the port clash. Default `up` skips it. profiles: ["edge"] image: caddy:2 restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" environment: PORTAL_HOST: ${PORTAL_HOST} ID_HOST: ${ID_HOST} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config depends_on: - portal - kanidm nats: image: nats:2.14.6-alpine restart: unless-stopped command: ["-c", "/etc/nats/nats.conf"] volumes: - ./nats/nats.conf:/etc/nats/nats.conf:ro - nats_data:/data # Published on the host so the reload job (`nats pub portal.content.reload ""`) # can reach it; password-protected (see nats.conf). Host port 4223, not 4222: # on kasse the shared platform NATS already owns 127.0.0.1:4222 and the vel # runs its own NATS in isolation, so the reload workflow targets 4223 there. # (Standalone, nothing else owns 4222, but 4223 is harmless.) ports: - "127.0.0.1:4223:4222" healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:8222/healthz"] interval: 10s timeout: 5s retries: 3 kanidm: image: kanidm/server:1.11.1 restart: unless-stopped environment: KANIDM_CONFIG_PATH: /data/server.toml volumes: - kanidm_data:/data - ./kanidm/server.toml:/data/server.toml:ro # Internal self-signed TLS: Caddy terminates the public # certificate and proxies here without verification. - ./certs/kanidm-chain.pem:/data/chain.pem:ro - ./certs/kanidm-key.pem:/data/key.pem:ro # Standalone (--profile edge): only the bundled Caddy talks to Kanidm. # On kasse the host Caddy fronts it, so publish loopback-only for a conf.d # entry: id. { reverse_proxy https://localhost:8443 { # transport http { tls_insecure_skip_verify } } } # (Kanidm's internal self-signed cert; 8443 is free on kasse — its shared # Kanidm is on 8310.) ports: - "127.0.0.1:8443:8443" portal: build: context: ./portal args: PORTAL_RELEASE: ${PORTAL_RELEASE} restart: unless-stopped env_file: portal.env environment: LEPTOS_SITE_ADDR: 0.0.0.0:3000 LEPTOS_SITE_ROOT: site LEPTOS_HASH_FILES: "true" ports: # Host-published for kasse's host Caddy (vel.klingenbergbygg.no -> here). # With --profile edge the bundled Caddy proxies portal:3000 internally # instead, but publishing loopback-only is harmless there. - "127.0.0.1:3050:3000" depends_on: nats: condition: service_healthy kanidm: condition: service_started # The Gitea Actions runner is a host service on kasse (pacman gitea-runner), # registered against prosjekt.klingenbergbygg.no. It reaches this NATS via the # published 127.0.0.1:4222 port above, so no in-compose runner — and no # docker.sock/podman.sock mount — is needed here. volumes: caddy_data: caddy_config: nats_data: kanidm_data: # Pin the project network subnet inside 172.16/12 so Kanidm's X-Forwarded-For # trust (kanidm/server.toml.tpl) stays valid under Podman — its default pool # hands out 10.89.x addresses that Caddy's forwarded client IP can't match. networks: default: ipam: config: - subnet: 172.18.0.0/16