diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 798700a..a77cfec 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -222,6 +222,7 @@ After Docker install, re-SSH so the `docker` group membership takes effect. | `abc_be` | django (docker) | all webservers | **beta only** | AI Benefits Coach API; no bundled Postgres; Ollama `http://10.0.0.128:11434`; shares DB `abc_be_beta` with `abc_worker` | | `abc_worker` | django-type compose (FastAPI) | all webservers | **beta only** | same Postgres as `abc_be`; `migrate_cmd: true`; WS on host port 8018 | | `abc_fe` | node-static (Vite) | all webservers | **beta only** | built to `/var/www/.abc.aimloperations/html`; no prod `host_apps` row | +| `livekit` | django-type compose (LiveKit SFU) | all webservers | **beta only** | Docker like `abc_worker`. Host network `:7880`. **Do not NPM-balance** until Redis — pick one upstream (adama). Router DNAT UDP 3478 + 50000–60000 and TCP 7881 to that host. Secrets `~/Documents/secrets/livekit/livekit_beta.env` | Django apps use a **shared external Postgres** (via `DATABASE_URL` in each host's env file) so active/active replicas share one database. Beta and prod never share @@ -258,6 +259,7 @@ future beta replica. | chat_web_app (nginx) | 8083 | 8082 | all webservers | | abc_fe (nginx) | **8085** | 8084 (*not deployed*) | all webservers | | dta_blog (nginx) | **8087** | **8086** | all webservers | +| livekit | **7880** | — | all webservers (signaling). UDP 3478 + 50000–60000 + TCP 7881 via router DNAT to the NPM upstream host | | SearxNG (LAN only) | — | **8088** | ai-server-4080 only (`searxng_stack`); not an NPM upstream | Host-local services on ai-server-4080 (not balanced by NPM): @@ -331,6 +333,7 @@ point each domain at the backend(s): | abc_fe | `beta.abc.aimloperations.com` (beta only) | `adama:8085` + same on roslin / starbuck / apollo / ai-server-4080 | | abc_be | `beta.abc.be.aimloperations.com` (beta only) | `adama:8017` + same on roslin / starbuck / apollo / ai-server-4080 | | abc_worker | `beta.abc.worker.aimloperations.com` (beta only; HTTP + WebSocket upgrade) | `adama:8018` + same on roslin / starbuck / apollo / ai-server-4080 | +| livekit | `LIVEKIT_DOMAIN` (e.g. `livekit.aimloperations.com`) — NPM Proxy Host, WebSocket, **single upstream** | `adama:7880` (do not balance until Redis) | ### Required changes IN each app repo (owned separately) @@ -440,6 +443,22 @@ Companion workflows: [abc_be#22](https://git.aimloperations.com/GIS/abc_be/issue [abc_worker#27](https://git.aimloperations.com/GIS/abc_worker/issues/27), [abc_fe#27](https://git.aimloperations.com/GIS/abc_fe/issues/27). +`livekit` (GIS org, SFU on webservers — [abc_worker#14](https://git.aimloperations.com/GIS/abc_worker/issues/14)–[#17](https://git.aimloperations.com/GIS/abc_worker/issues/17)): + +Control-node secret (never git, mode `600`): + +```text +~/Documents/secrets/livekit/livekit_beta.env +``` + +Template: `GIS/livekit` `.env.beta.example`. Same `LIVEKIT_API_KEY` / +`LIVEKIT_API_SECRET` pair as `abc_be` / `abc_worker`; worker `LIVEKIT_URL=wss://`. + +Deploy: `./scripts/deploy.sh --app livekit --env beta` (all webservers, like +`abc_worker`). NPM: `LIVEKIT_DOMAIN` → **one** host `:7880` with WebSocket +(adama). Router DNAT UDP 3478 + 50000–60000 and TCP 7881 to that same host. +Do not active/active-balance LiveKit until Redis is in the compose. + `dta_blog` ([#29](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/29)) — Python SSG, **no secrets file**. `npm run build:` writes `/var/www/.blog.realpath.app/html`. Prod (`:8086`) omits `demo: true` seed @@ -535,7 +554,8 @@ Store vault password for CI in a file readable only by the Act runner (e.g. `~/. | 10h | Register + deploy `college_craft` (django, ports 8006/8016) | Done ([#24](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/24)) | | 10i | Register + deploy ABC beta (`abc_be` 8017, `abc_worker` 8018, `abc_fe` 8085) | Done ([#26](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/26)) | | 10j | Register + deploy `print_forge` (django, ports 8007/8019) | Done ([#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27)) | -| 10k | Register + deploy `dta_blog` (node-static, ports 8086/8087) | This PR ([#29](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/29)) | +| 10k | Register + deploy `dta_blog` (node-static, ports 8086/8087) | Done ([#29](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/29)) | +| 10l | Register GIS LiveKit SFU (`abc_worker`-style docker on webservers, port 7880) | This PR | | 11 | Gitea container registry (optional) | Future | ## Open Decisions diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml index 0d9a66d..a89fd7e 100644 --- a/inventory/group_vars/all.yml +++ b/inventory/group_vars/all.yml @@ -12,6 +12,15 @@ ufw_allowed_tcp_ports: - 80 - 443 +# LiveKit on webservers. Signaling stays LAN (NPM → :7880). UDP must be +# reachable from the internet via router DNAT to the NPM upstream host. +ufw_lan_tcp_ports: + - 7880 + - 7881 +ufw_extra_udp_ports: + - 3478 + - "50000:60000" + # Docker docker_users: - "{{ admin_user }}" @@ -167,6 +176,14 @@ app_catalog: repo: "{{ git_base_url }}/GIS/abc_fe.git" default_branch: master webroot_pattern: "/var/www/{env}.abc.aimloperations/html" + livekit: + type: django + repo: "{{ git_base_url }}/GIS/livekit.git" + default_branch: master + compose_file: docker-compose.prod.yml + web_service: web + # SFU — no Django migrations. `true` keeps the django deploy path happy. + migrate_cmd: "true" # Deploy filter vars. CI passes these; manual runs may leave them undefined # to (re)deploy every app listed in the host's host_apps. diff --git a/inventory/host_vars/adama.yml b/inventory/host_vars/adama.yml index 5a4d9d5..bc0d0ea 100644 --- a/inventory/host_vars/adama.yml +++ b/inventory/host_vars/adama.yml @@ -31,3 +31,4 @@ host_apps: - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } + - { name: livekit, env: beta, port: 7880 } diff --git a/inventory/host_vars/ai-server-4080.yml b/inventory/host_vars/ai-server-4080.yml index bb4f78d..2272dfa 100644 --- a/inventory/host_vars/ai-server-4080.yml +++ b/inventory/host_vars/ai-server-4080.yml @@ -47,4 +47,5 @@ host_apps: - { name: print_forge, env: beta, port: 8019 } - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - - { name: abc_fe, env: beta, port: 8085 } \ No newline at end of file + - { name: abc_fe, env: beta, port: 8085 } + - { name: livekit, env: beta, port: 7880 } \ No newline at end of file diff --git a/inventory/host_vars/apollo.yml b/inventory/host_vars/apollo.yml index 242490a..f4e8442 100644 --- a/inventory/host_vars/apollo.yml +++ b/inventory/host_vars/apollo.yml @@ -27,3 +27,4 @@ host_apps: - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } + - { name: livekit, env: beta, port: 7880 } diff --git a/inventory/host_vars/roslin.yml b/inventory/host_vars/roslin.yml index f75fd6a..9b5a3ed 100644 --- a/inventory/host_vars/roslin.yml +++ b/inventory/host_vars/roslin.yml @@ -27,3 +27,4 @@ host_apps: - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } + - { name: livekit, env: beta, port: 7880 } diff --git a/inventory/host_vars/starbuck.yml b/inventory/host_vars/starbuck.yml index 377fa6c..c100736 100644 --- a/inventory/host_vars/starbuck.yml +++ b/inventory/host_vars/starbuck.yml @@ -27,3 +27,4 @@ host_apps: - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } + - { name: livekit, env: beta, port: 7880 } diff --git a/roles/ufw/tasks/main.yml b/roles/ufw/tasks/main.yml index 9ecf7c0..33b3117 100644 --- a/roles/ufw/tasks/main.yml +++ b/roles/ufw/tasks/main.yml @@ -28,6 +28,28 @@ proto: tcp loop: "{{ ufw_allowed_tcp_ports }}" +- name: Allow extra TCP ports + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: tcp + loop: "{{ ufw_extra_tcp_ports | default([]) }}" + +- name: Allow extra TCP ports from LAN + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: tcp + from_ip: "{{ ufw_ssh_allowed_network }}" + loop: "{{ ufw_lan_tcp_ports | default([]) }}" + +- name: Allow extra UDP ports or ranges + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: udp + loop: "{{ ufw_extra_udp_ports | default([]) }}" + - name: Enable UFW community.general.ufw: state: enabled diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 422a8eb..ff53447 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -17,7 +17,7 @@ Deploy applications with deploy-apps.yml. HOST Optional. Limit to one host: adama, roslin, starbuck, apollo, or ai-server-4080. Options: - --app NAME App to deploy (company_site, dta_service, dta_webapp, dta_blog, scha, chat_web_app, chat_backend, monica_site, url_shortening_service, college_craft, print_forge, abc_be, abc_worker, abc_fe) + --app NAME App to deploy (company_site, dta_service, dta_webapp, dta_blog, scha, chat_web_app, chat_backend, monica_site, url_shortening_service, college_craft, print_forge, abc_be, abc_worker, abc_fe, livekit) --env ENV Environment: beta or prod --ref REF Git ref/sha to deploy (default: master) --check Dry run