Files
pleskSaas/docs/deployment-production.md

158 lines
5.3 KiB
Markdown

# Production Deployment Runtime Foundation
This project can be deployed in a dedicated Proxmox container using Docker Compose. The files added here establish a minimal production runtime baseline without changing application business logic or Supabase security boundaries.
## Dockerfile purpose
The `Dockerfile` uses a multi-stage build on Node 20:
- installs dependencies
- runs `next build`
- prepares a lean runtime image with production dependencies
- runs the app with `next start` on port `3000`
This keeps the runtime image small and focused on serving the built Next.js app.
## docker-compose.prod.yml purpose
`docker-compose.prod.yml` defines one service:
- service name: `web`
- container name: `plesk-agency-portal`
- restart policy: `unless-stopped`
- environment from `.env`
- port mapping `3000:3000`
- health check against `/api/health`
## External Supabase requirement
Supabase remains external to this application container. The app container must only connect to Supabase via environment variables. No local Supabase container is included in this production compose file.
## Health endpoint usage
`GET /api/health` provides a fast, dependency-light runtime check for container orchestration and uptime checks.
Example:
```bash
curl -s http://localhost:3000/api/health
```
Expected response shape:
- `ok: true`
- `service: "plesk-agency-portal"`
- `timestamp`
- `environment`
## Production environment expectations
Before deploying, set production-safe values in `.env` (using `.env.example` as the template), including:
- app URL and `NODE_ENV`
- Supabase public and server credentials
- Plesk credential encryption key
- Stripe secrets
- cron/job shared secrets
Keep secrets out of source control.
## Reverse proxy assumptions (Nginx Proxy Manager)
This app is expected to run behind a reverse proxy in production.
- TLS is terminated at the proxy.
- Proxy forwards standard host/protocol headers (`Host`, `X-Forwarded-Proto`, `X-Forwarded-Host`).
- Public origin is configured explicitly with `NEXT_PUBLIC_APP_URL`.
To keep callback behavior stable behind proxy layers, auth redirect responses use the configured application origin from environment configuration rather than relying only on request host detection.
## Callback URL expectations
- `NEXT_PUBLIC_APP_URL` must be set to the public HTTPS URL used by users.
- Supabase auth redirect/callback configuration must allow:
- `<NEXT_PUBLIC_APP_URL>/auth/callback`
The callback route also validates the `next` parameter as an internal path to prevent unsafe external redirects.
## Cron protection expectations
Operational cron endpoints are protected with a shared secret.
- Required header: `x-cron-secret`
- Server secret source: `CRON_SHARED_SECRET`
- Backward compatibility fallback: `CRON_SECRET`
For new production setups, set `CRON_SHARED_SECRET` and use that value for all cron callers.
## Jenkins pipeline flow
The repository includes a declarative `Jenkinsfile` with the following stages:
1. **Checkout**
2. **Install dependencies** (`npm ci`)
3. **Lint** (runs only when `package.json` contains a `lint` script)
4. **Build application** (`npm run build`)
5. **Build Docker image** (tags `latest` and `build-${BUILD_NUMBER}`)
6. **Deploy** over SSH to the app host
7. **Smoke check** against `/api/health`
## Required Jenkins configuration
Configure these values in Jenkins job/folder/global environment or credentials-backed environment variables:
- `DEPLOY_SSH_HOST` - remote app host
- `DEPLOY_SSH_USER` - SSH user on remote host
- `DEPLOY_SSH_CREDENTIAL_ID` - Jenkins SSH Agent credential ID
- `DEPLOY_PATH` - remote deployment path (for example `/opt/plesk-agency-portal`)
- `APP_BASE_URL` - externally reachable app URL used by smoke check
The pipeline assumes Jenkins credentials are managed outside this repository.
Jenkins runtime requirements:
- The pipeline must run on a Jenkins agent with the `docker` label.
- That agent must have Docker CLI installed and permission to access Docker daemon/socket.
- `rsync` and `ssh` must also be available on the Jenkins agent.
If Docker is missing or inaccessible, the pipeline now fails early in a dedicated preflight stage with an explicit message.
## Deploy flow
Deployment is intentionally simple and bash-based:
1. Jenkins builds Docker image tags locally.
2. Jenkins syncs deployment files (`docker-compose.prod.yml`, deploy/smoke/rollback scripts) to the remote deploy path.
3. Jenkins streams Docker images to the remote host (`docker save | ssh docker load`).
4. Jenkins runs `scripts/deploy-prod.sh` remotely.
5. Script applies the selected image tag via:
```bash
APP_IMAGE=<tag> docker compose -f docker-compose.prod.yml up -d --no-build
```
6. Script prints `docker compose ps` status.
## Rollback flow
Rollback uses `scripts/rollback-prod.sh` with a previously built image tag:
```bash
DEPLOY_PATH=/opt/plesk-agency-portal \
APP_BASE_URL=https://your-app.example.com \
scripts/rollback-prod.sh plesk-agency-portal:build-123
```
Rollback redeploys that image with compose, then immediately reruns smoke checks.
## Smoke check behavior
`scripts/smoke-check.sh`:
- accepts a base URL argument
- requests `${BASE_URL}/api/health`
- fails on non-200 responses
- fails on invalid JSON or missing expected fields (`ok: true`, `service` string)
This gives a quick post-deploy validation gate for both deploy and rollback operations.