fix: map Docker nginx to port 8080 to avoid conflict with host reverse proxy

The base docker-compose.yml maps nginx to 80:80, which conflicts with
the host-level nginx that handles SSL termination on production servers.
The production overlay now explicitly maps to 8080:80 so the host proxy
can forward to localhost:8080. Updated DEPLOYMENT.md with host reverse
proxy setup instructions and corrected architecture diagrams.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 19:59:24 -05:00
parent 411239bea4
commit d526025926
2 changed files with 77 additions and 12 deletions

View File

@@ -10,10 +10,13 @@
# - Restart policies for reliability
#
# SSL/TLS is handled at the host level (e.g., host nginx + certbot).
# The Docker nginx container listens on port 80 only.
# The Docker nginx container listens internally on port 80, mapped to
# host port 8080 so it doesn't conflict with the host reverse proxy.
services:
nginx:
ports:
- "8080:80" # override: avoid conflict with host nginx
volumes:
- ./nginx/production.conf:/etc/nginx/conf.d/default.conf:ro
restart: unless-stopped

View File

@@ -171,14 +171,54 @@ nano .env
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
```
To add SSL on top of the production stack:
> **Port mapping:** The production overlay maps the Docker nginx to **host
> port 8080** (not 80) so it doesn't conflict with a host-level reverse
> proxy. If you're NOT using a host reverse proxy, you can override this:
> ```bash
> # Direct access on port 80 (no host reverse proxy)
> docker compose -f docker-compose.yml -f docker-compose.prod.yml \
> up -d --build --scale nginx=0
> # Then manually: docker compose ... run -d -p 80:80 nginx
> ```
### Host reverse proxy setup (recommended)
In production, SSL termination is typically handled by a **host-level nginx**
(or Caddy, Traefik, etc.) that proxies to the Docker stack on port 8080:
```nginx
# /etc/nginx/sites-available/app.yourdomain.com
server {
listen 80;
server_name app.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name app.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
Then enable and reload:
```bash
docker compose \
-f docker-compose.yml \
-f docker-compose.prod.yml \
-f docker-compose.ssl.yml \
up -d --build
sudo ln -s /etc/nginx/sites-available/app.yourdomain.com /etc/nginx/sites-enabled/
sudo certbot --nginx -d app.yourdomain.com # if using certbot on host
sudo nginx -t && sudo systemctl reload nginx
```
> **Tip:** Create a shell alias to avoid typing the compose files every time:
@@ -690,8 +730,9 @@ docker compose logs -f nginx # nginx access/error log
## Architecture Overview
```
Development:
┌──────────────────┐
Browser ─────────► │ nginx :80/:443
Browser ─────────► │ nginx :80
└────────┬─────────┘
┌──────────┴──────────┐
▼ ▼
@@ -701,10 +742,31 @@ docker compose logs -f nginx # nginx access/error log
└──────┬───────┘ └──────────────┘
┌────┴────┐
▼ ▼
┌────────────┐ ┌───────────┐ ┌───────────┐
│postgres:5432│ │redis :6379│ │ certbot │
│ (PG 15) │ │ (Redis 7) │ │ (renewal) │
└────────────┘ └───────────┘ └───────────┘
┌────────────┐ ┌───────────┐
│postgres:5432│ │redis :6379│
│ (PG 15) │ │ (Redis 7) │
└────────────┘ └───────────┘
Production (with host reverse proxy):
┌──────────────────────┐
Browser ─────────► │ Host nginx :80/:443 │ ← SSL termination
└────────┬─────────────┘
┌──────────────────┐
│ Docker nginx:8080│ ← proxy to services
└────────┬─────────┘
┌──────────┴──────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ backend :3000│ │frontend :3001│
│ (compiled) │ │ (static nginx)│
└──────┬───────┘ └──────────────┘
┌────┴────┐
▼ ▼
┌────────────┐ ┌───────────┐
│postgres:5432│ │redis :6379│
│ (PG 15) │ │ (Redis 7) │
└────────────┘ └───────────┘
```
**Multi-tenant isolation:** Each HOA organization gets its own PostgreSQL