Files
veridian/DEPLOY.md
T
zoeissleeping 30a425744d feat: add startup migration script and improve Docker setup
- Add scripts/start.ts to run drizzle migrations before server start
- Update Dockerfile to copy migration files and install prod deps
- Change entrypoint to use migration-aware startup script
- Add deployment documentation
2026-05-11 17:43:13 -05:00

4.3 KiB

Deploying Veridian

Self-hosted deployment guide using Docker Compose on a VPS.

Prerequisites

  • A VPS with Docker and Docker Compose installed
  • A domain name pointed at your VPS IP address
  • An external reverse proxy (Caddy, Nginx, etc.) for HTTPS termination

First Deploy

1. Clone the repository

git clone https://gitea.wildcardproject.com/zoeissleeping/veridian.git
cd veridian

2. Configure environment variables

cp .env.example .env

Edit .env and set the required values:

# Generate a secure auth secret
openssl rand -base64 32

# Set these in .env
POSTGRES_PASSWORD=<your-secure-db-password>
BETTER_AUTH_SECRET=<output from openssl>
NUXT_PUBLIC_URL=https://your-domain.com

3. Build and start

docker compose up --build -d

This will:

  1. Build the Nuxt application
  2. Start PostgreSQL and wait for it to be healthy
  3. Run all pending database migrations automatically
  4. Start the application server

4. Verify

# Check container status
docker compose ps

# Check app logs (should show migration + server start)
docker compose logs app

# Check for errors
docker compose logs app | grep -i error

5. Set up your reverse proxy

Point your reverse proxy at 127.0.0.1:3000. Example Caddy config:

your-domain.com {
    reverse_proxy 127.0.0.1:3000
}

Updating

When you pull new changes:

git pull

# Rebuild and restart (migrations run automatically on startup)
docker compose up --build -d

The app container will:

  1. Rebuild with the latest code
  2. Run any new migrations that were added
  3. Restart the server

Database Migrations

Migrations run automatically every time the app container starts, via scripts/start.ts. This uses Drizzle ORM's programmatic migration API (drizzle-orm/node-postgres/migrator).

  • First deploy: All migrations run, creating all tables
  • Updates: Only new/pending migrations run
  • No changes: Migrations are a no-op

If a migration fails, the app will not start and the container will exit with an error. Check logs with:

docker compose logs app

Creating new migrations

After modifying drizzle/schema.ts:

bunx drizzle-kit generate

This creates a new SQL file in drizzle/migrations/. Commit it to git. It will be applied automatically on next deploy.

Database Backups

Manual backup

docker compose exec db pg_dump -U postgres veridian > backup_$(date +%Y%m%d).sql

Restore from backup

cat backup_20250101.sql | docker compose exec -T db psql -U postgres veridian

Automated backups (optional)

Add a cron job on the host:

# Daily backup at 3 AM
0 3 * * * cd /path/to/veridian && docker compose exec -T db pg_dump -U postgres veridian | gzip > /var/backups/veridian/veridian_$(date +\%Y\%m\%d).sql.gz

Troubleshooting

App won't start

# Check logs
docker compose logs app

# Common issues:
# - Missing .env file or required variables not set
# - Database not reachable (check db container is healthy)
# - Migration errors (schema conflicts)

Database connection refused

# Check DB is healthy
docker compose ps db

# Check DB logs
docker compose logs db

# Test connection
docker compose exec db psql -U postgres veridian -c "SELECT 1"

Reset database (destructive)

docker compose down -v  # Removes volumes!
docker compose up --build -d

Environment Variables Reference

Variable Required Description
POSTGRES_DB No Database name (default: veridian)
POSTGRES_USER No Database user (default: postgres)
POSTGRES_PASSWORD Yes Database password
DATABASE_URL Auto Built from the above vars by docker-compose
BETTER_AUTH_SECRET Yes Auth encryption secret (openssl rand -base64 32)
NUXT_PUBLIC_URL Yes Public URL (e.g., https://veridian.example.com)
S3_ACCESS_KEY_ID No S3-compatible storage access key
S3_SECRET_ACCESS_KEY No S3-compatible storage secret key
S3_BUCKET_NAME No S3 bucket name
S3_REGION No S3 region
S3_ENDPOINT No S3 endpoint URL
DISABLE_SIGNUP No Set to true to disable new user signups
DISABLE_LOCAL_AUTH No Set to true to disable email/password auth