2026-07-16 06:19:58 -04:00
# Deployment Guide
2026-07-24 07:08:29 -04:00
Deploy Project E with Docker Compose and a reverse proxy such as Nginx Proxy Manager. Compose runs three services: the Next.js web app, PostgreSQL 16, and the background worker.
2026-07-16 06:19:58 -04:00
## Prerequisites
2026-07-24 07:08:29 -04:00
- Docker 24.0 or later
- Docker Compose 2.20 or later
- A reverse proxy for TLS and public routing
- At least 1 GB RAM and 10 GB disk space
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## Deploy Project E
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
1. Clone the repository on the server.
2026-07-16 06:19:58 -04:00
```bash
git clone <repository-url>
cd ProjectE
` ``
2026-07-24 07:08:29 -04:00
2. Create the environment file.
2026-07-16 06:19:58 -04:00
` ``bash
cp .env.example .env
` ``
2026-07-24 07:08:29 -04:00
3. Set the required values in ` .env`.
2026-07-16 06:19:58 -04:00
` ``bash
2026-07-24 07:08:29 -04:00
POSTGRES_PASSWORD=your_postgres_password
DATABASE_URL=postgresql://project_e:your_postgres_password@localhost:5432/project_e
NEXTAUTH_SECRET=your_long_random_secret
INITIAL_ADMIN_EMAIL=admin@example.com
INITIAL_ADMIN_PASSWORD=your_initial_admin_password
PUBLIC_URL=https://project-e.example.com
COOKIE_SECURE=true
ALLOWED_HOSTS=project-e.example.com
2026-07-16 06:19:58 -04:00
` ``
2026-07-24 07:08:29 -04:00
Generate secrets with ` openssl rand -base64 32`. Use the same ` POSTGRES_PASSWORD` in ` DATABASE_URL`. The web and worker containers use an internal database URL that Compose builds from ` POSTGRES_PASSWORD`.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
4. Build and start the services.
2026-07-16 06:19:58 -04:00
` ``bash
docker compose up -d
` ``
2026-07-24 07:08:29 -04:00
5. Confirm that the services are healthy.
2026-07-16 06:19:58 -04:00
` ``bash
docker compose ps
` ``
2026-07-24 07:08:29 -04:00
6. Route your domain to ` project-e-web:3000` through your reverse proxy.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
7. Open the app and sign in with ` INITIAL_ADMIN_EMAIL` and ` INITIAL_ADMIN_PASSWORD`. Project E creates that account only when the database contains no users.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## Environment variables
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
| Variable | Required | Description |
|----------|----------|-------------|
| ` DATABASE_URL` | Yes | PostgreSQL connection string for local tools and processes outside Compose. |
| ` POSTGRES_PASSWORD` | Yes | Password for the ` project_e` PostgreSQL user. |
| ` NEXTAUTH_SECRET` | Yes | Secret used to sign NextAuth JWT sessions. |
| ` INITIAL_ADMIN_EMAIL` | Yes | Email address for the first account. |
| ` INITIAL_ADMIN_PASSWORD` | Yes | Password for the first account. |
| ` PUBLIC_URL` | No | Public application URL. Defaults to ` http://localhost:3000`. |
| ` COOKIE_SECURE` | No | Set to ` true` behind HTTPS. Defaults to ` false`. |
| ` ALLOWED_HOSTS` | No | Comma-separated allowed hostnames. |
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
Keep ` .env` out of version control. Rotate ` NEXTAUTH_SECRET` only when you intend to end active sessions.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## PostgreSQL and Drizzle
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
The ` db` service runs ` postgres:16-alpine`, stores its data in the ` project-e-pg-data` Docker volume, and exposes port 5432. The web and worker services connect to ` db:5432` over the Compose network.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
Docker mounts ` drizzle/0000_first_mauler.sql` into PostgreSQL's initialization directory. PostgreSQL runs that file only while it initializes an empty data volume. For a later Drizzle migration, apply the reviewed SQL as part of your release process. Do not expect a container restart to apply a new migration to an existing volume.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
To apply a migration from the host, run:
2026-07-16 06:19:58 -04:00
` ``bash
2026-07-24 07:08:29 -04:00
docker compose exec -T db psql -U project_e -d project_e < drizzle/<migration>.sql
2026-07-16 06:19:58 -04:00
` ``
2026-07-24 07:08:29 -04:00
Back up the database before applying schema changes.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## Nginx Proxy Manager
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
1. In Nginx Proxy Manager, open **Hosts** > **Proxy Hosts** > **Add Proxy Host**.
2. Set the domain name, choose ` http`, set the forward hostname to ` project-e-web`, and set the forward port to ` 3000`.
3. Select a certificate and force SSL for HTTPS deployments.
4. Add the following advanced configuration to support Server-Sent Events:
2026-07-16 06:19:58 -04:00
` ``nginx
proxy_http_version 1.1;
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 Host $host;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
` ``
2026-07-24 07:08:29 -04:00
5. Save the host and open the configured domain. You should reach the Project E sign-in page.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## Back up and restore PostgreSQL
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
Create a logical backup without stopping the database:
2026-07-16 06:19:58 -04:00
` ``bash
2026-07-24 07:08:29 -04:00
mkdir -p backups
2026-07-16 06:19:58 -04:00
` ``
2026-07-24 07:08:29 -04:00
Restore a backup into a new or empty database:
2026-07-16 06:19:58 -04:00
` ``bash
2026-07-24 07:08:29 -04:00
docker compose exec -T db psql -U project_e -d project_e < backups/project-e-YYYYMMDD_HHMMSS.sql
2026-07-16 06:19:58 -04:00
` ``
2026-07-24 07:08:29 -04:00
Back up the ` project-e-web-uploads` volume if your deployment stores uploads there:
2026-07-16 06:19:58 -04:00
` ``bash
docker run --rm \
-v project-e-web-uploads:/source:ro \
-v $(pwd)/backups:/backup \
alpine \
tar czf /backup/uploads-$(date +%Y%m%d).tar.gz -C /source .
` ``
2026-07-24 07:08:29 -04:00
Test restores on a separate environment before relying on a backup.
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## Monitoring and logs
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
Check service status and logs:
2026-07-16 06:19:58 -04:00
` ``bash
docker compose ps
` ``
2026-07-24 07:08:29 -04:00
The web service exposes ` GET /api/health` on port 3000. Configure uptime monitoring for ` https://your-domain.example/api/health`.
2026-07-16 06:19:58 -04:00
## Troubleshooting
2026-07-24 07:08:29 -04:00
| Problem | Fix |
|---------|-----|
| Database connection fails | Confirm that ` db` is healthy and that ` POSTGRES_PASSWORD` matches the value in ` DATABASE_URL`. |
| The web service will not start | Set ` NEXTAUTH_SECRET`, ` INITIAL_ADMIN_EMAIL`, and ` INITIAL_ADMIN_PASSWORD` in ` .env`, then restart the service. |
| Sign-in fails | Confirm the email and password match the initial-admin values. Those values create an account only before any user exists. |
| A schema change is missing | Apply the generated Drizzle SQL. PostgreSQL initialization scripts do not rerun for an existing volume. |
| Realtime updates stop | Disable proxy buffering and set a read timeout of at least 300 seconds. |
| Disk space runs low | Inspect ` project-e-pg-data` and ` project-e-web-uploads`, back up data, and expand the host disk. |
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
## Scaling
2026-07-16 06:19:58 -04:00
2026-07-24 07:08:29 -04:00
The default deployment runs one web service, one worker, and one PostgreSQL instance. Add CPU and memory before changing the topology. Multiple web services require shared session-aware infrastructure and a reverse proxy that supports long-lived SSE connections. Multiple workers coordinate through the PostgreSQL-backed job records.