Add production Traefik compose and domain deployment steps
This commit is contained in:
parent
edceb48da0
commit
3202899d76
|
|
@ -18,3 +18,7 @@ POSTGRES_PASSWORD=CHANGE_ME_TO_A_STRONG_PASSWORD
|
|||
|
||||
# Front-end URL used by CORS
|
||||
FRONTEND_PUBLIC_URL=https://seu-dominio.com
|
||||
|
||||
# Domain / HTTPS (docker-compose.prod.yml)
|
||||
API_DOMAIN=api.seu-dominio.com
|
||||
ACME_EMAIL=seu-email@seu-dominio.com
|
||||
|
|
|
|||
67
DEPLOY.md
67
DEPLOY.md
|
|
@ -5,7 +5,7 @@ Esse erro acontece quando o `docker compose` é executado em uma pasta sem `dock
|
|||
|
||||
Este repositório inclui `docker-compose.yml` na raiz do projeto.
|
||||
|
||||
## Passo a passo
|
||||
## Opção 1: subir via IP (rápido)
|
||||
|
||||
1. Entre na pasta da API:
|
||||
|
||||
|
|
@ -39,6 +39,41 @@ docker compose logs -f --tail=200
|
|||
curl -I http://SEU_SERVIDOR:4000/health
|
||||
```
|
||||
|
||||
## Opção 2: subir já com domínio + HTTPS automático (Traefik)
|
||||
|
||||
### Pré-requisitos
|
||||
- O DNS do domínio/subdomínio da API deve apontar para o IP do servidor (registro `A`).
|
||||
- Portas 80 e 443 abertas no firewall/security group.
|
||||
|
||||
### 1) Ajuste o `.env`
|
||||
Na pasta da API:
|
||||
|
||||
```bash
|
||||
cd ~/apps/line-gestao-api
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
```
|
||||
|
||||
Preencha obrigatoriamente:
|
||||
- `API_DOMAIN` (ex.: `api.seudominio.com`)
|
||||
- `ACME_EMAIL` (email para emitir certificado)
|
||||
- `FRONTEND_PUBLIC_URL` (URL pública do front)
|
||||
- `JWT_KEY`, `SEED_ADMIN_*`, `POSTGRES_PASSWORD`
|
||||
|
||||
### 2) Suba em modo produção com Traefik
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml up -d --build
|
||||
```
|
||||
|
||||
### 3) Verifique saúde e certificado
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml ps
|
||||
docker compose -f docker-compose.prod.yml logs -f --tail=200
|
||||
curl -i https://SEU_API_DOMAIN/health
|
||||
```
|
||||
|
||||
## Checklist de confirmação (API realmente no ar)
|
||||
Considere que o deploy está concluído quando **todos** os itens abaixo estiverem OK:
|
||||
|
||||
|
|
@ -48,32 +83,38 @@ curl -i http://127.0.0.1:4000/health
|
|||
curl -i http://SEU_IP_PUBLICO:4000/health
|
||||
```
|
||||
|
||||
Para produção com domínio:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml ps
|
||||
curl -i https://SEU_API_DOMAIN/health
|
||||
```
|
||||
|
||||
Resultado esperado:
|
||||
- container `linegestao-api` com status `healthy`;
|
||||
- container `linegestao-db` com status `healthy`;
|
||||
- endpoint `/health` respondendo `HTTP/1.1 200 OK`.
|
||||
|
||||
## Domínio (DNS + proxy reverso)
|
||||
Com o compose atual, a API está disponível em `http://SEU_IP:4000`.
|
||||
Para usar domínio em produção, faça:
|
||||
|
||||
1. Crie/ajuste o DNS do domínio para apontar para o IP do servidor (registro `A`).
|
||||
2. Coloque um proxy reverso na frente da API (Nginx, Traefik ou Caddy).
|
||||
3. Emita TLS/HTTPS (Let's Encrypt).
|
||||
4. Atualize `FRONTEND_PUBLIC_URL` no `.env` para a URL pública do front-end.
|
||||
|
||||
Sem proxy+HTTPS, o domínio pode até abrir via HTTP, mas não é recomendado para produção.
|
||||
|
||||
## Atualizando um clone já existente no servidor
|
||||
|
||||
```bash
|
||||
cd ~/apps/line-gestao-api
|
||||
git fetch --all --prune
|
||||
git pull --rebase origin NOME_DA_BRANCH
|
||||
```
|
||||
|
||||
Depois de atualizar, suba com o arquivo que você usa:
|
||||
|
||||
```bash
|
||||
# modo IP
|
||||
docker compose up -d --build
|
||||
|
||||
# modo domínio + HTTPS
|
||||
docker compose -f docker-compose.prod.yml up -d --build
|
||||
```
|
||||
|
||||
## Observações
|
||||
- O Postgres **não é exposto** para fora do Docker (sem `5432:5432`).
|
||||
- A API sobe na porta `4000` do host (`4000:8080`).
|
||||
- No modo IP, a API sobe na porta `4000` do host (`4000:8080`).
|
||||
- No modo domínio, a API fica atrás do Traefik em `443` (HTTPS).
|
||||
- Defina valores fortes para `JWT_KEY`, `SEED_ADMIN_PASSWORD` e `POSTGRES_PASSWORD`.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
services:
|
||||
traefik:
|
||||
image: traefik:v3.3
|
||||
container_name: linegestao-traefik
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --certificatesresolvers.letsencrypt.acme.tlschallenge=true
|
||||
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL:?ACME_EMAIL is required}
|
||||
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- traefik_letsencrypt:/letsencrypt
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
container_name: linegestao-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-linegestao}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-linegestao_app}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
|
||||
volumes:
|
||||
- pg_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-linegestao_app} -d ${POSTGRES_DB:-linegestao}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: linegestao-api
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT:-Production}
|
||||
App__UseHttpsRedirection: ${APP_USE_HTTPS_REDIRECTION:-false}
|
||||
ConnectionStrings__Default: Host=db;Port=5432;Database=${POSTGRES_DB:-linegestao};Username=${POSTGRES_USER:-linegestao_app};Password=${POSTGRES_PASSWORD}
|
||||
Jwt__Key: ${JWT_KEY:?JWT_KEY is required}
|
||||
Jwt__Issuer: ${JWT_ISSUER:-LineGestao}
|
||||
Jwt__Audience: ${JWT_AUDIENCE:-LineGestao}
|
||||
Seed__AdminEmail: ${SEED_ADMIN_EMAIL:?SEED_ADMIN_EMAIL is required}
|
||||
Seed__AdminPassword: ${SEED_ADMIN_PASSWORD:?SEED_ADMIN_PASSWORD is required}
|
||||
Cors__AllowedOrigins__0: ${FRONTEND_PUBLIC_URL:?FRONTEND_PUBLIC_URL is required}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.linegestao-api.rule=Host(`${API_DOMAIN:?API_DOMAIN is required}`)
|
||||
- traefik.http.routers.linegestao-api.entrypoints=websecure
|
||||
- traefik.http.routers.linegestao-api.tls.certresolver=letsencrypt
|
||||
- traefik.http.services.linegestao-api.loadbalancer.server.port=8080
|
||||
|
||||
volumes:
|
||||
pg_data:
|
||||
traefik_letsencrypt:
|
||||
Loading…
Reference in New Issue