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:
@@ -10,10 +10,13 @@
|
|||||||
# - Restart policies for reliability
|
# - Restart policies for reliability
|
||||||
#
|
#
|
||||||
# SSL/TLS is handled at the host level (e.g., host nginx + certbot).
|
# 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:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
|
ports:
|
||||||
|
- "8080:80" # override: avoid conflict with host nginx
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx/production.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./nginx/production.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -171,14 +171,54 @@ nano .env
|
|||||||
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
|
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
|
```bash
|
||||||
docker compose \
|
sudo ln -s /etc/nginx/sites-available/app.yourdomain.com /etc/nginx/sites-enabled/
|
||||||
-f docker-compose.yml \
|
sudo certbot --nginx -d app.yourdomain.com # if using certbot on host
|
||||||
-f docker-compose.prod.yml \
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
-f docker-compose.ssl.yml \
|
|
||||||
up -d --build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Tip:** Create a shell alias to avoid typing the compose files every time:
|
> **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
|
## 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 │
|
│postgres:5432│ │redis :6379│
|
||||||
│ (PG 15) │ │ (Redis 7) │ │ (renewal) │
|
│ (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
|
**Multi-tenant isolation:** Each HOA organization gets its own PostgreSQL
|
||||||
|
|||||||
Reference in New Issue
Block a user