Register dta_blog for node-static deploy (closes #29) (#30)
Sync runner checkout / sync (push) Successful in 7s
Sync runner checkout / sync (push) Successful in 7s
## Summary - Closes [#29](#29). - Register `dta_blog` in `app_catalog` (`type: node-static`, repo `Ditch_The_Agent/dta_blog`, default branch `main`, webroot `/var/www/{env}.blog.realpath.app/html`). Reuses `roles/app-deploy/tasks/node_static.yml` (`npm ci` then `npm run build:<env>`); the blog's `package.json` copies `dist/` to that webroot after `python3 build.py --env <env>`. - Add prod **8086** / beta **8087** `host_apps` on adama, roslin, starbuck, apollo, and ai-server-4080 (those ports were free vs 8080–8085 / 8088). - Optional nginx `error_page 404 /404.html` for this app only (`error_page_404` catalog field); other static apps keep the SPA `try_files` fallback. - Document NPM/DNS (`blog.realpath.app` → `:8086`, `beta.blog.realpath.app` → `:8087`), no `realpath.app/blog` mount, and UFW staying LAN/NPM-only. ## Test plan - [ ] Confirm 8086/8087 unused on app hosts before first deploy. - [ ] `./scripts/deploy.sh --app dta_blog --env beta --ref main` publishes `/var/www/beta.blog.realpath.app/html`. - [ ] `./scripts/deploy.sh --app dta_blog --env prod --ref main` publishes `/var/www/prod.blog.realpath.app/html`. - [ ] **Until [dta_blog#1](Ditch_The_Agent/dta_blog#1) is on `main`**, use `--ref issue-1-static-blog` so the SSG (not the stub README) is built. - [ ] NPM + DNS + TLS: `blog.realpath.app` → `:8086`, `beta.blog.realpath.app` → `:8087`. Do not reverse-proxy onto `realpath.app/blog`. - [ ] Prod HTML has article text, Tianji id `cmtvvmf562afjzqumwt1yh2y8`, links to `https://realpath.app/`. - [ ] Beta HTML has Tianji id `cmtvvn6z62agdzqumtk8xijpy`, links to `https://beta.realpath.app/`, demo posts present. - [ ] `https://blog.realpath.app/sitemap.xml`, `robots.txt`, `llms.txt` return 200. - [ ] Unknown slug returns 404.html (not the index SPA fallback). Reviewed-on: #30
This commit was merged in pull request #30.
This commit is contained in:
+28
-3
@@ -211,6 +211,7 @@ After Docker install, re-SSH so the `docker` group membership takes effect.
|
||||
| `company_site` | django (docker) | all webservers | prod | active/active behind NPM; beta port reserved |
|
||||
| `dta_service` | django (docker) | all webservers | beta + prod | active/active behind NPM |
|
||||
| `dta_webapp` | node/vite static | all webservers | beta + prod | active/active; built to `/var/www/<env>.realpath.app/html`, served by web-static nginx |
|
||||
| `dta_blog` | node-static (Python SSG) | all webservers | beta + prod | active/active; built to `/var/www/<env>.blog.realpath.app/html`; **own hosts** (`blog.realpath.app` / `beta.blog.realpath.app`), not `realpath.app/blog`; Tianji ids baked at build |
|
||||
| `scha` | django (docker) | all webservers | prod | active/active behind NPM; beta port reserved |
|
||||
| `chat_web_app` | node-static (CRA) | all webservers | beta + prod | active/active; built to `/var/www/<env>.chat.aimloperations/html`, served by web-static nginx |
|
||||
| `chat_backend` | django (docker) | all webservers | beta + prod | active/active behind NPM; Ollama `http://10.0.0.128:11434`; SearxNG `http://10.0.0.128:8088` (`SEARXNG_BASE_URL`) |
|
||||
@@ -256,6 +257,7 @@ future beta replica.
|
||||
| dta_webapp (nginx) | 8081 | 8080 | all webservers |
|
||||
| chat_web_app (nginx) | 8083 | 8082 | all webservers |
|
||||
| abc_fe (nginx) | **8085** | 8084 (*not deployed*) | all webservers |
|
||||
| dta_blog (nginx) | **8087** | **8086** | all webservers |
|
||||
| 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):
|
||||
@@ -293,8 +295,10 @@ chat_backend secrets must use `SEARXNG_BASE_URL=http://10.0.0.128:8088`.
|
||||
`compose_profiles: [worker]` so deploy starts dj-queue with web. Other hosts
|
||||
omit profiles (web only).
|
||||
- **node-static**: git checkout at ref → `npm ci` → `npm run build:<env>`
|
||||
(writes to the app's `webroot_pattern`, e.g. `/var/www/{env}.realpath.app/html`
|
||||
or `/var/www/{env}.chat.aimloperations/html`).
|
||||
(writes to the app's `webroot_pattern`, e.g. `/var/www/{env}.realpath.app/html`,
|
||||
`/var/www/{env}.blog.realpath.app/html`, or `/var/www/{env}.chat.aimloperations/html`).
|
||||
Optional catalog `error_page_404` (used by `dta_blog`) serves that file instead
|
||||
of the SPA `/index.html` fallback.
|
||||
- **web-static** role: one nginx container per app host serving the static roots
|
||||
on their ports (from `host_apps`); NPM balances across hosts. Before `compose up`,
|
||||
removes any container currently publishing those host ports (`docker ps --filter
|
||||
@@ -315,6 +319,7 @@ point each domain at the backend(s):
|
||||
| company_site | aimloperations.com (+ www) | `adama:8000` + `roslin:8000` + `starbuck:8000` + `apollo:8000` |
|
||||
| dta_service | (see DTA NPM hosts) | `adama:8001` / `8011` + same on roslin / starbuck / apollo / ai-server-4080 |
|
||||
| dta_webapp | (see DTA NPM hosts) | `adama:8080` / `8081` + same on roslin / starbuck / apollo |
|
||||
| dta_blog | `blog.realpath.app` (prod); `beta.blog.realpath.app` (beta). **Do not** reverse-proxy onto `realpath.app/blog` | `adama:8086` / `8087` + same on roslin / starbuck / apollo / ai-server-4080 |
|
||||
| scha | `schawheaton.aimloperations.com`, `schawheaton.com` (+ www) | `adama:8002` + `roslin:8002` + `starbuck:8002` + `apollo:8002` (+ `ai-server-4080:8002`) |
|
||||
| chat_web_app | `chat.aimloperations.com` (+ www); `beta.chat.aimloperations.com` | `adama:8082` / `8083` + same on roslin / starbuck / apollo / ai-server-4080 |
|
||||
| chat_backend | `chatbackend.aimloperations.com`; `beta.chatbackend.aimloperations.com` | `adama:8003` / `8013` + same on roslin / starbuck / apollo / ai-server-4080 |
|
||||
@@ -337,6 +342,9 @@ point each domain at the backend(s):
|
||||
(keep the test/docker jobs).
|
||||
- [ ] `dta_webapp`: `npm run build:beta` / `build:prod` output to
|
||||
`/var/www/beta.realpath.app/html` / `/var/www/prod.realpath.app/html`.
|
||||
- [ ] `dta_blog`: `npm run build:beta` / `build:prod` output to
|
||||
`/var/www/beta.blog.realpath.app/html` / `/var/www/prod.blog.realpath.app/html`
|
||||
(`python3 build.py --env <env>` copies `dist/`). Default branch is `main`.
|
||||
- [ ] `chat_web_app`: `npm run build:beta` / `build:prod` output to
|
||||
`/var/www/beta.chat.aimloperations/html` / `/var/www/prod.chat.aimloperations/html`.
|
||||
|
||||
@@ -432,6 +440,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).
|
||||
|
||||
`dta_blog` ([#29](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/29)) —
|
||||
Python SSG, **no secrets file**. `npm run build:<env>` writes
|
||||
`/var/www/<env>.blog.realpath.app/html`. Prod (`:8086`) omits `demo: true` seed
|
||||
posts; beta (`:8087`) includes them. Header/footer links are baked at build
|
||||
(`https://realpath.app` vs `https://beta.realpath.app`); Tianji website ids
|
||||
are likewise baked (`cmtvvmf562afjzqumwt1yh2y8` / `cmtvvn6z62agdzqumtk8xijpy`).
|
||||
Default branch is `main`.
|
||||
|
||||
NPM / DNS / Cloudflare (Ansible does not manage these): `blog.realpath.app` →
|
||||
`:8086`, `beta.blog.realpath.app` → `:8087`, TLS like the other RealPath names.
|
||||
Do **not** mount this on `realpath.app/blog`. Static ports stay LAN / NPM-only
|
||||
(UFW does not world-open 8086/8087).
|
||||
|
||||
Companion app ticket: [dta_blog#1](https://git.aimloperations.com/Ditch_The_Agent/dta_blog/issues/1).
|
||||
Gitea deploy can later call `./scripts/deploy.sh --app dta_blog --env beta|prod`.
|
||||
|
||||
### One-time host bootstrap (per target)
|
||||
|
||||
- [x] Gitea SSH key: the `gitea-key` role (in `site.yml`) generates a key per
|
||||
@@ -510,7 +534,8 @@ Store vault password for CI in a file readable only by the Act runner (e.g. `~/.
|
||||
| 10g | Register + deploy `url_shortening_service` (django, ports 8005/8015) | Done ([#22](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/22)) |
|
||||
| 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) | This PR ([#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27)) |
|
||||
| 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)) |
|
||||
| 11 | Gitea container registry (optional) | Future |
|
||||
|
||||
## Open Decisions
|
||||
|
||||
@@ -80,6 +80,15 @@ app_catalog:
|
||||
webroot_pattern: "/var/www/{env}.realpath.app/html"
|
||||
# deploy runs `npm ci` then `npm run build:<env>`; that script writes to
|
||||
# {{ web_static_root }}/<env>_dta_webapp (beta/prod), served by web-static.
|
||||
dta_blog:
|
||||
type: node-static
|
||||
repo: "{{ git_base_url }}/Ditch_The_Agent/dta_blog.git"
|
||||
default_branch: main
|
||||
# Python SSG (stdlib). package.json build:<env> copies dist/ to this webroot
|
||||
# so the existing node-static path (`npm ci` then `npm run build:<env>`) works.
|
||||
webroot_pattern: "/var/www/{env}.blog.realpath.app/html"
|
||||
# Real 404 page (not SPA index fallback). See roles/web-static nginx.conf.j2.
|
||||
error_page_404: /404.html
|
||||
scha:
|
||||
type: django
|
||||
repo: "{{ git_base_url }}/ai_ml_operations/scha.git"
|
||||
|
||||
@@ -11,6 +11,8 @@ host_apps:
|
||||
- { name: dta_service, env: beta, port: 8011 }
|
||||
- { name: dta_webapp, env: prod, port: 8080 }
|
||||
- { name: dta_webapp, env: beta, port: 8081 }
|
||||
- { name: dta_blog, env: prod, port: 8086 }
|
||||
- { name: dta_blog, env: beta, port: 8087 }
|
||||
- { name: scha, env: prod, port: 8002 }
|
||||
# optional: - { name: scha, env: beta, port: 8012 }
|
||||
- { name: chat_web_app, env: prod, port: 8082 }
|
||||
|
||||
@@ -27,6 +27,8 @@ host_apps:
|
||||
- { name: company_site, env: prod, port: 8000 }
|
||||
- { name: dta_webapp, env: prod, port: 8080 }
|
||||
- { name: dta_webapp, env: beta, port: 8081 }
|
||||
- { name: dta_blog, env: prod, port: 8086 }
|
||||
- { name: dta_blog, env: beta, port: 8087 }
|
||||
- { name: dta_service, env: prod, port: 8001 }
|
||||
- { name: dta_service, env: beta, port: 8011 }
|
||||
- { name: scha, env: prod, port: 8002 }
|
||||
|
||||
@@ -7,6 +7,8 @@ host_apps:
|
||||
- { name: dta_service, env: beta, port: 8011 }
|
||||
- { name: dta_webapp, env: prod, port: 8080 }
|
||||
- { name: dta_webapp, env: beta, port: 8081 }
|
||||
- { name: dta_blog, env: prod, port: 8086 }
|
||||
- { name: dta_blog, env: beta, port: 8087 }
|
||||
- { name: scha, env: prod, port: 8002 }
|
||||
# optional: - { name: scha, env: beta, port: 8012 }
|
||||
- { name: chat_web_app, env: prod, port: 8082 }
|
||||
|
||||
@@ -7,6 +7,8 @@ host_apps:
|
||||
- { name: dta_service, env: beta, port: 8011 }
|
||||
- { name: dta_webapp, env: prod, port: 8080 }
|
||||
- { name: dta_webapp, env: beta, port: 8081 }
|
||||
- { name: dta_blog, env: prod, port: 8086 }
|
||||
- { name: dta_blog, env: beta, port: 8087 }
|
||||
- { name: scha, env: prod, port: 8002 }
|
||||
# optional: - { name: scha, env: beta, port: 8012 }
|
||||
- { name: chat_web_app, env: prod, port: 8082 }
|
||||
|
||||
@@ -7,6 +7,8 @@ host_apps:
|
||||
- { name: dta_service, env: beta, port: 8011 }
|
||||
- { name: dta_webapp, env: prod, port: 8080 }
|
||||
- { name: dta_webapp, env: beta, port: 8081 }
|
||||
- { name: dta_blog, env: prod, port: 8086 }
|
||||
- { name: dta_blog, env: beta, port: 8087 }
|
||||
- { name: scha, env: prod, port: 8002 }
|
||||
# optional: - { name: scha, env: beta, port: 8012 }
|
||||
- { name: chat_web_app, env: prod, port: 8082 }
|
||||
|
||||
@@ -30,9 +30,17 @@ server {
|
||||
root {{ (app_catalog[a.name].webroot_pattern | default(web_static_root ~ '/{env}_' ~ a.name)) | replace('{env}', a.env) }};
|
||||
index index.html;
|
||||
|
||||
{% if app_catalog[a.name].error_page_404 | default('') %}
|
||||
error_page 404 {{ app_catalog[a.name].error_page_404 }};
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
{% else %}
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
location ~* \.(?:js|css|woff2?|png|jpg|jpeg|gif|svg|ico)$ {
|
||||
expires 7d;
|
||||
|
||||
+1
-1
@@ -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, 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)
|
||||
--env ENV Environment: beta or prod
|
||||
--ref REF Git ref/sha to deploy (default: master)
|
||||
--check Dry run
|
||||
|
||||
Reference in New Issue
Block a user