compose: web/admin com roteador e certificado próprios (v4.4)

This commit is contained in:
Erico Mac
2026-10-06 17:38:40 -03:00
parent edce7120d8
commit 6057114288
2 changed files with 64 additions and 16 deletions
+32 -8
View File
@@ -89,7 +89,7 @@ services:
- '5000' - '5000'
ingestor: ingestor:
# DRENAGEM do ONE (passagens + fotos). Valores de cadência da produção antiga. # DRENAGEM do ONE (passagens + fotos). Valores de cadência da produção antiga.
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
# Só ORDEM de partida, sem `condition: service_healthy`: a espera de verdade é # Só ORDEM de partida, sem `condition: service_healthy`: a espera de verdade é
# dentro do container (`wait-for-db schema rabbitmq`). Com a condição aqui, o # dentro do container (`wait-for-db schema rabbitmq`). Com a condição aqui, o
@@ -128,7 +128,7 @@ services:
MINIO_BUCKET: rastro-photos MINIO_BUCKET: rastro-photos
command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/ingestor start"' command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/ingestor start"'
migrate: migrate:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: 'no' restart: 'no'
depends_on: depends_on:
- db - db
@@ -141,7 +141,7 @@ services:
DB_CONNECTION_LIMIT: '5' DB_CONNECTION_LIMIT: '5'
command: 'sh -c "wait-for-db && pnpm --filter @rastro/db migrate && pnpm --filter @rastro/db postgis && pnpm --filter @rastro/db timescale && pnpm --filter @rastro/db intel && pnpm --filter @rastro/db analyze && pnpm --filter @rastro/db restore-users"' command: 'sh -c "wait-for-db && pnpm --filter @rastro/db migrate && pnpm --filter @rastro/db postgis && pnpm --filter @rastro/db timescale && pnpm --filter @rastro/db intel && pnpm --filter @rastro/db analyze && pnpm --filter @rastro/db restore-users"'
processor: processor:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
@@ -168,7 +168,7 @@ services:
command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/processor start"' command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/processor start"'
dfe-worker: dfe-worker:
# Cadeia MDF-e → CT-e → NF-e (SEFAZ; Teradata para transporte além de D+1) + rota OSRM. # Cadeia MDF-e → CT-e → NF-e (SEFAZ; Teradata para transporte além de D+1) + rota OSRM.
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
@@ -226,7 +226,7 @@ services:
TERADATA_USER: '${TERADATA_USER}' TERADATA_USER: '${TERADATA_USER}'
TERADATA_PASSWORD: '${TERADATA_PASSWORD}' TERADATA_PASSWORD: '${TERADATA_PASSWORD}'
backend: backend:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
@@ -284,6 +284,7 @@ services:
- 'traefik.http.routers.rastroapi.rule=(Host(`${WEB_DOMAIN}`) || Host(`${ADMIN_DOMAIN}`)) && PathPrefix(`/api`)' - 'traefik.http.routers.rastroapi.rule=(Host(`${WEB_DOMAIN}`) || Host(`${ADMIN_DOMAIN}`)) && PathPrefix(`/api`)'
- traefik.http.routers.rastroapi.entryPoints=https - traefik.http.routers.rastroapi.entryPoints=https
- traefik.http.routers.rastroapi.tls=true - traefik.http.routers.rastroapi.tls=true
- traefik.http.routers.rastroapi.tls.certresolver=letsencrypt
- traefik.http.routers.rastroapi.priority=1000 - traefik.http.routers.rastroapi.priority=1000
- traefik.http.routers.rastroapi.service=rastroapi - traefik.http.routers.rastroapi.service=rastroapi
- traefik.http.services.rastroapi.loadbalancer.server.port=39010 - traefik.http.services.rastroapi.loadbalancer.server.port=39010
@@ -296,7 +297,7 @@ services:
- traefik.http.routers.rastroapicampo.priority=1000 - traefik.http.routers.rastroapicampo.priority=1000
- traefik.http.routers.rastroapicampo.service=rastroapi - traefik.http.routers.rastroapicampo.service=rastroapi
web: web:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
environment: environment:
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public' DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public'
@@ -308,8 +309,22 @@ services:
command: 'sh -c "pnpm --filter web preview --host 0.0.0.0 --port 39000"' command: 'sh -c "pnpm --filter web preview --host 0.0.0.0 --port 39000"'
expose: expose:
- '39000' - '39000'
labels:
# O endereço sai de WEB_DOMAIN, a MESMA variável que o site usa para aceitar o
# host e que o /api usa na regra do Traefik. Enquanto o domínio era atribuído na
# tela do Coolify, os dois podiam divergir — e divergiram: a tela tinha
# `rastro.cfi…`, a variável `rastrobr.cfi…`, resultado 403 num nome e 503 no outro.
- traefik.enable=true
- 'traefik.http.routers.rastroweb.rule=Host(`${WEB_DOMAIN}`)'
- traefik.http.routers.rastroweb.entryPoints=https
- traefik.http.routers.rastroweb.tls=true
- traefik.http.routers.rastroweb.tls.certresolver=letsencrypt
# Prioridade baixa: o /api do backend (1000) tem de ganhar no mesmo domínio.
- traefik.http.routers.rastroweb.priority=10
- traefik.http.routers.rastroweb.service=rastroweb
- traefik.http.services.rastroweb.loadbalancer.server.port=39000
admin: admin:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
environment: environment:
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public' DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public'
@@ -321,12 +336,21 @@ services:
command: 'sh -c "pnpm --filter admin preview --host 0.0.0.0 --port 39020"' command: 'sh -c "pnpm --filter admin preview --host 0.0.0.0 --port 39020"'
expose: expose:
- '39020' - '39020'
labels:
- traefik.enable=true
- 'traefik.http.routers.rastroadmin.rule=Host(`${ADMIN_DOMAIN}`)'
- traefik.http.routers.rastroadmin.entryPoints=https
- traefik.http.routers.rastroadmin.tls=true
- traefik.http.routers.rastroadmin.tls.certresolver=letsencrypt
- traefik.http.routers.rastroadmin.priority=10
- traefik.http.routers.rastroadmin.service=rastroadmin
- traefik.http.services.rastroadmin.loadbalancer.server.port=39020
# Rastro Campo — PWA da fiscalização volante. O endereço sai da variável # Rastro Campo — PWA da fiscalização volante. O endereço sai da variável
# CAMPO_DOMAIN: basta defini-la e apontar o DNS, SEM configurar domínio na tela do # CAMPO_DOMAIN: basta defini-la e apontar o DNS, SEM configurar domínio na tela do
# Coolify (como o /api do backend já faz). HTTPS é obrigatório — sem ele o # Coolify (como o /api do backend já faz). HTTPS é obrigatório — sem ele o
# navegador não libera a câmera. # navegador não libera a câmera.
campo: campo:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
environment: environment:
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public' DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public'
+32 -8
View File
@@ -89,7 +89,7 @@ services:
- '5000' - '5000'
ingestor: ingestor:
# DRENAGEM do ONE (passagens + fotos). Valores de cadência da produção antiga. # DRENAGEM do ONE (passagens + fotos). Valores de cadência da produção antiga.
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
# Só ORDEM de partida, sem `condition: service_healthy`: a espera de verdade é # Só ORDEM de partida, sem `condition: service_healthy`: a espera de verdade é
# dentro do container (`wait-for-db schema rabbitmq`). Com a condição aqui, o # dentro do container (`wait-for-db schema rabbitmq`). Com a condição aqui, o
@@ -128,7 +128,7 @@ services:
MINIO_BUCKET: rastro-photos MINIO_BUCKET: rastro-photos
command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/ingestor start"' command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/ingestor start"'
migrate: migrate:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: 'no' restart: 'no'
depends_on: depends_on:
- db - db
@@ -141,7 +141,7 @@ services:
DB_CONNECTION_LIMIT: '5' DB_CONNECTION_LIMIT: '5'
command: 'sh -c "wait-for-db && pnpm --filter @rastro/db migrate && pnpm --filter @rastro/db postgis && pnpm --filter @rastro/db timescale && pnpm --filter @rastro/db intel && pnpm --filter @rastro/db analyze && pnpm --filter @rastro/db restore-users"' command: 'sh -c "wait-for-db && pnpm --filter @rastro/db migrate && pnpm --filter @rastro/db postgis && pnpm --filter @rastro/db timescale && pnpm --filter @rastro/db intel && pnpm --filter @rastro/db analyze && pnpm --filter @rastro/db restore-users"'
processor: processor:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
@@ -168,7 +168,7 @@ services:
command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/processor start"' command: 'sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/processor start"'
dfe-worker: dfe-worker:
# Cadeia MDF-e → CT-e → NF-e (SEFAZ; Teradata para transporte além de D+1) + rota OSRM. # Cadeia MDF-e → CT-e → NF-e (SEFAZ; Teradata para transporte além de D+1) + rota OSRM.
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
@@ -226,7 +226,7 @@ services:
TERADATA_USER: '${TERADATA_USER}' TERADATA_USER: '${TERADATA_USER}'
TERADATA_PASSWORD: '${TERADATA_PASSWORD}' TERADATA_PASSWORD: '${TERADATA_PASSWORD}'
backend: backend:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
@@ -284,6 +284,7 @@ services:
- 'traefik.http.routers.rastroapi.rule=(Host(`${WEB_DOMAIN}`) || Host(`${ADMIN_DOMAIN}`)) && PathPrefix(`/api`)' - 'traefik.http.routers.rastroapi.rule=(Host(`${WEB_DOMAIN}`) || Host(`${ADMIN_DOMAIN}`)) && PathPrefix(`/api`)'
- traefik.http.routers.rastroapi.entryPoints=https - traefik.http.routers.rastroapi.entryPoints=https
- traefik.http.routers.rastroapi.tls=true - traefik.http.routers.rastroapi.tls=true
- traefik.http.routers.rastroapi.tls.certresolver=letsencrypt
- traefik.http.routers.rastroapi.priority=1000 - traefik.http.routers.rastroapi.priority=1000
- traefik.http.routers.rastroapi.service=rastroapi - traefik.http.routers.rastroapi.service=rastroapi
- traefik.http.services.rastroapi.loadbalancer.server.port=39010 - traefik.http.services.rastroapi.loadbalancer.server.port=39010
@@ -296,7 +297,7 @@ services:
- traefik.http.routers.rastroapicampo.priority=1000 - traefik.http.routers.rastroapicampo.priority=1000
- traefik.http.routers.rastroapicampo.service=rastroapi - traefik.http.routers.rastroapicampo.service=rastroapi
web: web:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
environment: environment:
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public' DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public'
@@ -308,8 +309,22 @@ services:
command: 'sh -c "pnpm --filter web preview --host 0.0.0.0 --port 39000"' command: 'sh -c "pnpm --filter web preview --host 0.0.0.0 --port 39000"'
expose: expose:
- '39000' - '39000'
labels:
# O endereço sai de WEB_DOMAIN, a MESMA variável que o site usa para aceitar o
# host e que o /api usa na regra do Traefik. Enquanto o domínio era atribuído na
# tela do Coolify, os dois podiam divergir — e divergiram: a tela tinha
# `rastro.cfi…`, a variável `rastrobr.cfi…`, resultado 403 num nome e 503 no outro.
- traefik.enable=true
- 'traefik.http.routers.rastroweb.rule=Host(`${WEB_DOMAIN}`)'
- traefik.http.routers.rastroweb.entryPoints=https
- traefik.http.routers.rastroweb.tls=true
- traefik.http.routers.rastroweb.tls.certresolver=letsencrypt
# Prioridade baixa: o /api do backend (1000) tem de ganhar no mesmo domínio.
- traefik.http.routers.rastroweb.priority=10
- traefik.http.routers.rastroweb.service=rastroweb
- traefik.http.services.rastroweb.loadbalancer.server.port=39000
admin: admin:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
environment: environment:
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public' DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public'
@@ -321,12 +336,21 @@ services:
command: 'sh -c "pnpm --filter admin preview --host 0.0.0.0 --port 39020"' command: 'sh -c "pnpm --filter admin preview --host 0.0.0.0 --port 39020"'
expose: expose:
- '39020' - '39020'
labels:
- traefik.enable=true
- 'traefik.http.routers.rastroadmin.rule=Host(`${ADMIN_DOMAIN}`)'
- traefik.http.routers.rastroadmin.entryPoints=https
- traefik.http.routers.rastroadmin.tls=true
- traefik.http.routers.rastroadmin.tls.certresolver=letsencrypt
- traefik.http.routers.rastroadmin.priority=10
- traefik.http.routers.rastroadmin.service=rastroadmin
- traefik.http.services.rastroadmin.loadbalancer.server.port=39020
# Rastro Campo — PWA da fiscalização volante. O endereço sai da variável # Rastro Campo — PWA da fiscalização volante. O endereço sai da variável
# CAMPO_DOMAIN: basta defini-la e apontar o DNS, SEM configurar domínio na tela do # CAMPO_DOMAIN: basta defini-la e apontar o DNS, SEM configurar domínio na tela do
# Coolify (como o /api do backend já faz). HTTPS é obrigatório — sem ele o # Coolify (como o /api do backend já faz). HTTPS é obrigatório — sem ele o
# navegador não libera a câmera. # navegador não libera a câmera.
campo: campo:
image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.3' image: 'gitea.externo.utic.app.br/ericoalmeida/rastro-node:v4.4'
restart: unless-stopped restart: unless-stopped
environment: environment:
DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public' DATABASE_URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public'