diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 69f7d1e..8bd98f6 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -30,7 +30,7 @@ concurrency: env: API_HOST: slartibartfast.kosherinata.internal WEB_HOST: oolon.kosherinata.internal - API_PORT: "8081" + API_PORT: "22672" SSH_OPTS: -o StrictHostKeyChecking=accept-new jobs: diff --git a/CLAUDE.md b/CLAUDE.md index 72cb7d3..ca51894 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -57,7 +57,8 @@ Crypto/token logic lives in `core::auth`; the flow orchestration in `core::servi api + worker → `slartibartfast.kosherinata.internal`; SPA → `oolon.kosherinata.internal` (nginx serves + proxies `/v1` to the API over the mesh; TLS terminates at oolon). API -port 8081, plain HTTP behind firewalld. See `.gitea/workflows/deploy.yml` (infra truth) +port 22672 (registered in architecture `port-allocations.md`; deliberately not the crowded +`8081`), plain HTTP behind firewalld. See `.gitea/workflows/deploy.yml` (infra truth) and `script/infra-setup.sh` (one-time host prep). `Type=exec`, not `notify`, because axum doesn't `sd_notify`. diff --git a/asset/config/config.toml.tmpl b/asset/config/config.toml.tmpl index 66e4b1d..17c86d9 100644 --- a/asset/config/config.toml.tmpl +++ b/asset/config/config.toml.tmpl @@ -7,7 +7,7 @@ # Bind the mesh-routable address so the oolon proxy can reach it. firewalld # (newsfeed-api service) bounds who may connect; TLS terminates at oolon. -bind = "0.0.0.0:8081" +bind = "0.0.0.0:22672" database_path = "/var/lib/newsfeed/newsfeed.db" session_ttl_days = 30 diff --git a/asset/firewalld/newsfeed-api.xml b/asset/firewalld/newsfeed-api.xml index 2bdbe56..e095257 100644 --- a/asset/firewalld/newsfeed-api.xml +++ b/asset/firewalld/newsfeed-api.xml @@ -3,5 +3,5 @@ newsfeed-api newsfeed REST/JSON API. Reached over the WireGuard mesh by the oolon edge proxy, which terminates TLS and reverse-proxies to this port. - + diff --git a/asset/nginx/newsfeed.internal.conf b/asset/nginx/newsfeed.internal.conf index 3c07638..8219b53 100644 --- a/asset/nginx/newsfeed.internal.conf +++ b/asset/nginx/newsfeed.internal.conf @@ -7,7 +7,7 @@ # ln -sf ../sites-available/newsfeed.internal.conf /etc/nginx/sites-enabled/ upstream newsfeed_api { - server slartibartfast.kosherinata.internal:8081; + server slartibartfast.kosherinata.internal:22672; keepalive 16; } diff --git a/crates/newsfeed-api/src/config.rs b/crates/newsfeed-api/src/config.rs index 6dab44b..663e80f 100644 --- a/crates/newsfeed-api/src/config.rs +++ b/crates/newsfeed-api/src/config.rs @@ -30,7 +30,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { - bind: "127.0.0.1:8081".parse().expect("valid default bind addr"), + bind: "127.0.0.1:22672".parse().expect("valid default bind addr"), database_path: PathBuf::from("/var/lib/newsfeed/newsfeed.db"), session_ttl_days: 30, max_db_connections: 5, @@ -42,7 +42,7 @@ impl Default for Config { impl Config { /// Load configuration, layering an optional TOML file and the environment over the - /// defaults. Env vars are `NEWSFEED_` prefixed (e.g. `NEWSFEED_BIND=0.0.0.0:8081`). + /// defaults. Env vars are `NEWSFEED_` prefixed (e.g. `NEWSFEED_BIND=0.0.0.0:22672`). pub fn load(file: Option<&Path>) -> anyhow::Result { let mut fig = Figment::from(Serialized::defaults(Config::default())); if let Some(path) = file { diff --git a/readme.md b/readme.md index a44e3e6..cda8fe3 100644 --- a/readme.md +++ b/readme.md @@ -65,9 +65,9 @@ cd web && pnpm install && pnpm build ## Run locally ```sh -# 1. API (creates ./data/newsfeed.db, binds 127.0.0.1:8081) +# 1. API (creates ./data/newsfeed.db, binds 127.0.0.1:22672) NEWSFEED_DATABASE_PATH=./data/newsfeed.db \ -NEWSFEED_BIND=127.0.0.1:8081 \ +NEWSFEED_BIND=127.0.0.1:22672 \ NEWSFEED_COOKIE_SECURE=false \ cargo run -p newsfeed-api -- --config /nonexistent @@ -75,7 +75,7 @@ NEWSFEED_COOKIE_SECURE=false \ NEWSFEED_DATABASE_PATH=./data/newsfeed.db \ cargo run -p newsfeed-worker -- --config /nonexistent -# 3. Frontend dev server (proxies /v1 and /health to :8081) +# 3. Frontend dev server (proxies /v1 and /health to :22672) cd web && pnpm dev ``` @@ -86,19 +86,19 @@ non-existent `--config` path just uses defaults + env, which is convenient for d ```sh # register + login (cookie jar) -curl -c cj -X POST localhost:8081/v1/auth/register -H content-type:application/json \ +curl -c cj -X POST localhost:22672/v1/auth/register -H content-type:application/json \ -d '{"username":"me","email":"me@example.com","password":"hunter2hunter2"}' -curl -c cj -X POST localhost:8081/v1/auth/login -H content-type:application/json \ +curl -c cj -X POST localhost:22672/v1/auth/login -H content-type:application/json \ -d '{"identifier":"me","password":"hunter2hunter2"}' # weight an interest, mint an ingest token -curl -b cj -X PUT localhost:8081/v1/interests -H content-type:application/json -d '{"label":"rust","weight":0.9}' -TOKEN=$(curl -b cj -X POST localhost:8081/v1/tokens -H content-type:application/json -d '{"name":"agent"}' | jq -r .secret) +curl -b cj -X PUT localhost:22672/v1/interests -H content-type:application/json -d '{"label":"rust","weight":0.9}' +TOKEN=$(curl -b cj -X POST localhost:22672/v1/tokens -H content-type:application/json -d '{"name":"agent"}' | jq -r .secret) # an agent pushes a candidate; read the ranked feed -curl -X POST localhost:8081/v1/ingest/candidates -H "authorization: Bearer $TOKEN" \ +curl -X POST localhost:22672/v1/ingest/candidates -H "authorization: Bearer $TOKEN" \ -H content-type:application/json -d '{"external_id":"a1","title":"Rust 2.0 released"}' -curl -b cj localhost:8081/v1/feed +curl -b cj localhost:22672/v1/feed ``` ## API surface (`/v1`) diff --git a/script/infra-setup.sh b/script/infra-setup.sh index be43249..17947c4 100755 --- a/script/infra-setup.sh +++ b/script/infra-setup.sh @@ -9,7 +9,7 @@ # * a scoped /etc/sudoers.d/newsfeed_gitea_ci drop-in (visudo-verified) # and per role: # * API host (slartibartfast): the `newsfeed` service account, /etc/newsfeed + -# /var/lib/newsfeed, SELinux port label for 8081, firewalld service +# /var/lib/newsfeed, SELinux port label for 22672, firewalld service # * WEB host (oolon): /var/www/newsfeed webroot, the internal `newsfeed.internal` TLS # cert (lair provisioner) + step@newsfeed renewal, and the nginx vhost # @@ -19,7 +19,7 @@ set -euo pipefail # --- infra truth (edit here if the topology changes) ------------------------------- API_HOST="slartibartfast.kosherinata.internal" # newsfeed-api + newsfeed-worker WEB_HOST="oolon.kosherinata.internal" # nginx: SPA + API reverse proxy -API_PORT="8081" +API_PORT="22672" CERT_NAME="newsfeed" # dot-free; serves ${CERT_NAME}.internal PUBLIC_FQDN="rob.fyi" # WAN name (Let's Encrypt); "" to skip CERT_EMAIL="ops@rob.fyi" # certbot registration email diff --git a/web/vite.config.ts b/web/vite.config.ts index 41cbb63..ed8aae3 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -9,8 +9,8 @@ export default defineConfig({ server: { port: 5173, proxy: { - '/v1': 'http://127.0.0.1:8081', - '/health': 'http://127.0.0.1:8081', + '/v1': 'http://127.0.0.1:22672', + '/health': 'http://127.0.0.1:22672', }, }, build: {