# Docker production – Strapi CMS

Production stack: **Meilisearch** + **Strapi** in Docker; **PostgreSQL on the machine** (host).

## 1. Configure environment

```bash
cp .env.production.example .env
# Edit .env: set STRAPI_PUBLIC_URL, FRONTEND_URL, DATABASE_*, and all secrets
```

Required in `.env`:

- `STRAPI_PUBLIC_URL` – public URL of this CMS (e.g. `https://cms.yourdomain.com`)
- `FRONTEND_URL` – frontend URL (e.g. `https://yourdomain.com`) for CORS / revalidation
- `DATABASE_HOST` – use `host.docker.internal` (default) so Strapi in Docker reaches Postgres on the host
- `DATABASE_PORT`, `DATABASE_NAME`, `DATABASE_USERNAME`, `DATABASE_PASSWORD` – your machine’s Postgres
- Strapi secrets: `APP_KEYS`, `API_TOKEN_SALT`, `ADMIN_JWT_SECRET`, `TRANSFER_TOKEN_SALT`, `ENCRYPTION_KEY`, `JWT_SECRET`

**Host Postgres:** Ensure PostgreSQL on the machine accepts TCP connections (e.g. `listen_addresses = '*'` in `postgresql.conf`) and allows connections from Docker (e.g. in `pg_hba.conf`: `host all all 172.17.0.0/16 scram-sha-256` or your Docker bridge subnet).

## 2. Build and run

```bash
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d
```

- Strapi: **http://localhost:1337** (bind to host). Put a reverse proxy (Apache/Nginx) in front.
- Meilisearch runs in Docker (internal network). Postgres runs on the machine; Strapi connects via `host.docker.internal`.

## 3. Reverse proxy

Point your CMS domain to the host and proxy to Strapi:

- **Apache:** `ProxyPass / http://127.0.0.1:1337/` and `ProxyPassReverse / http://127.0.0.1:1337/`
- **Nginx:** `proxy_pass http://127.0.0.1:1337;`

Ensure `STRAPI_PUBLIC_URL` in `.env` matches the public URL (e.g. `https://cms.yourdomain.com`).

## 4. Useful commands

```bash
# Logs
docker compose -f docker-compose.prod.yml logs -f strapi

# Stop (frees port 1337 and 7700)
docker compose -f docker-compose.prod.yml down

# Stop and remove volumes (⚠️ data loss)
docker compose -f docker-compose.prod.yml down -v
```

### Port already in use

If something else is using port 1337 (or 7700):

```bash
# Stop the prod stack (Strapi + Meilisearch)
docker compose -f docker-compose.prod.yml down

# Or find and kill whatever is on 1337 (Linux)
sudo lsof -i :1337
sudo kill -9 <PID>
```

### Build fails with "DNS: transient error" or "no such package"

The build needs to reach Alpine’s package servers. If DNS/network is flaky:

1. **Retry:** `docker compose -f docker-compose.prod.yml build --no-cache`
2. **Use host network during build:** `docker compose -f docker-compose.prod.yml build --no-cache` with `DOCKER_BUILDKIT=1 docker build --network=host` (build the image with `docker build --network=host -f Dockerfile .` from the project dir, then run compose up).

## 5. Using a remote database (e.g. managed Postgres)

If Postgres is on another host (e.g. AWS RDS) instead of the same machine:

1. Set in `.env`: `DATABASE_HOST=your-db-host`, and optionally `DATABASE_PORT`, `DATABASE_SSL=true`.
2. Run as usual: `docker compose -f docker-compose.prod.yml up -d`. Strapi will use `DATABASE_HOST` from `.env`.
</think>
Adding a short "External database" section and updating the README.
<｜tool▁calls▁begin｜><｜tool▁call▁begin｜>
StrReplace