Deploying ezRepo
ezRepo's Compose stack starts PostgreSQL, applies Prisma migrations once, and then starts the API and web applications. It does not terminate TLS. Put the web and API services behind a reverse proxy that owns the public hostname and certificates.
Prerequisites
- Docker Engine with Docker Compose v2.
- A DNS record for the public hostname.
- A reverse proxy that obtains and renews TLS certificates.
- A private server directory readable only by deployment administrators.
The Compose stack persists PostgreSQL data, including normalized user profile pictures, in its named ezrepo-postgres volume. Do not delete this volume unless you intentionally want to remove all ezRepo data.
First deployment
Check out a released ezRepo version and create the private environment file:
bashcp .env.example .env chmod 600 .envReplace every placeholder in
.env, especiallyPOSTGRES_PASSWORD, both database URLs,AUTH_JWT_SECRET, andTOKEN_ENCRYPTION_KEY. Generate the encryption key with:bashopenssl rand -base64 32Set the externally visible URLs. For a deployment at
https://ezrepo.example.com, use:dotenvPUBLIC_URL=https://ezrepo.example.com OIDC_CALLBACK_URL=https://ezrepo.example.com/api/v1/auth/oidc/callback CORS_ORIGIN=https://ezrepo.example.com NUXT_PUBLIC_API_BASE_URL=https://ezrepo.example.com/api/v1 OAUTH_CALLBACK_URL=https://ezrepo.example.com/api/v1/provider-accounts/oauth/callbackBind the container ports to loopback when the reverse proxy runs on the same host:
dotenvEZREPO_API_PORT=127.0.0.1:3001 EZREPO_WEB_PORT=127.0.0.1:3000Otherwise, restrict access to ports 3000 and 3001 with the host firewall. Never expose the PostgreSQL container.
Set
EZREPO_VERSIONin.envto an exact released image pair, then start the stack:bashdocker compose pull docker compose up --detach --waitKeep that value in
.envso every later Compose command uses the same API and web version.Confirm the API health endpoint locally:
bashcurl --fail http://127.0.0.1:3001/api/healthOpen the public ezRepo URL and complete the one-time first-run setup to create the first system administrator.
Reverse proxy and TLS
Proxy the public web origin to port 3000, and the API and Socket.IO paths to port 3001. For example, a Caddy site block can use:
ezrepo.example.com {
reverse_proxy /api/* 127.0.0.1:3001
reverse_proxy /socket.io/* 127.0.0.1:3001
reverse_proxy 127.0.0.1:3000
}The proxy must redirect HTTP to HTTPS, validate upstream connections according to its local policy, and preserve the public hostname. Configure OAuth providers with the same HTTPS callback URL set in OAUTH_CALLBACK_URL.
Upgrading
Migrating an earlier installation
ezRepo is a clean-cut rename. Before upgrading an earlier installation, create a verified PostgreSQL dump, stop the old stack, and retain TOKEN_ENCRYPTION_KEY. Configure the new EZREPO_* variables, ezrepo-postgres volume, and ezRepo image names, then restore the dump into the new database before starting ezRepo. The migration invalidates browser sessions because the JWT issuer and browser storage keys changed; users must sign in again.
Create and verify a database backup before changing images.
Set
EZREPO_VERSIONto the exact release version in.env.Pull and apply the release:
bashdocker compose pull docker compose up --detach --waitThe
migrateservice applies pending Prisma migrations before the API starts. Inspect it after every update:bashdocker compose logs migrateVerify the health endpoint and the proxy-served dashboard before considering the update complete.
Database backup
Run backups from the deployment directory. This writes a PostgreSQL custom-format dump to the host without printing credentials or putting them in the command line:
mkdir -p backups
backup_file="backups/ezrepo-$(date +%F-%H%M%S).dump"
docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -Fc "$POSTGRES_DB"' \
> "$backup_file"
pg_restore --list "$backup_file"Store encrypted copies off-host and periodically test restores on a separate system.
Database restore
Restoring replaces current database objects. Take a new backup first and schedule downtime.
docker compose stop api web
docker compose exec -T postgres sh -c 'pg_restore -U "$POSTGRES_USER" --clean --if-exists --no-owner -d "$POSTGRES_DB"' \
< backups/ezrepo-YYYY-MM-DD-HHMMSS.dump
docker compose up --detach --waitAfterward, check docker compose logs migrate and the API health endpoint. Restore a dump made by a compatible ezRepo version when rolling back across schema changes.
Rollback
- Keep the backup made immediately before the failed upgrade.
- Set
EZREPO_VERSIONin.envto the last known-good image version. - Run
docker compose pullanddocker compose up --detach --wait. - If the newer release migrated the database incompatibly, stop API and web, restore the compatible backup, and then start the previous image version again.
Never use docker compose down --volumes as an update or rollback command: it removes the named PostgreSQL volume.