HoMee Events

Deployment

HoMeeSuite is distributed as a set of Docker images and orchestrated with Docker Compose. This guide covers everything a system administrator needs to get a production instance running.

Prerequisites

  • Docker 24+ and Docker Compose v2
  • A server with at least 1 GB RAM and 10 GB disk space
  • A domain name pointed at the server (required for TLS and email links)
  • An SMTP server or relay (optional, but required for email notifications)

Quick start

1. Create the working directory

mkdir homeesuite && cd homeesuite

2. Create the docker-compose.yml

services:
  nextjs:
    image: ghcr.io/your-org/homeesuite:latest   # replace with your image tag
    restart: unless-stopped
    environment:
      DATABASE_URL: postgresql://homeesuite:${POSTGRES_PASSWORD}@postgres:5432/homeesuite
      REDIS_URL: redis://redis:6379
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
      BETTER_AUTH_URL: https://your-domain.example.com
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      NODE_ENV: production
    volumes:
      - uploads_data:/app/public/uploads
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:3000/api/health || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  bullmq-worker:
    image: ghcr.io/your-org/homeesuite:latest
    restart: unless-stopped
    command: node worker.js
    environment:
      DATABASE_URL: postgresql://homeesuite:${POSTGRES_PASSWORD}@postgres:5432/homeesuite
      REDIS_URL: redis://redis:6379
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      NODE_ENV: production
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: homeesuite
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: homeesuite
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U homeesuite"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
  redis_data:
  uploads_data:

3. Create the .env file

# Generate BETTER_AUTH_SECRET:
#   node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
BETTER_AUTH_SECRET=<32-char-random-hex>

# Generate ENCRYPTION_KEY the same way:
ENCRYPTION_KEY=<32-char-random-hex>

POSTGRES_PASSWORD=<strong-random-password>

Keep this file outside version control. Both secret values must be at least 32 characters of random data.

4. Start the services

docker compose up -d

5. Run database migrations

Migrations run automatically on first startup as part of the Next.js build entrypoint. Wait for the nextjs container to reach healthy status:

docker compose ps

6. Complete first-run setup

Open https://your-domain.example.com/setup in a browser. The setup wizard only appears when no Superadmin account exists yet. Create the first Superadmin user here — this is the account you will use to manage users, groups, and global settings.

Once saved, the /setup route redirects to login permanently.

Environment variables reference

Variable Required Description
DATABASE_URL Yes PostgreSQL connection string
REDIS_URL Yes Redis connection string for BullMQ
BETTER_AUTH_SECRET Yes Secret key for session signing (min 32 chars)
BETTER_AUTH_URL Yes Public URL of the application (used in email links)
BETTER_AUTH_TRUSTED_ORIGINS No Comma-separated list of additional trusted origins, e.g. https://homee.rocks,https://holtermeeting.de — needed when the same instance is reachable under multiple domains
ENCRYPTION_KEY Yes Key for encrypting sensitive fields (min 32 chars)
SMTP_HOST No SMTP server hostname — can also be set from Admin → Settings
SMTP_PORT No SMTP port (default: 587)
SMTP_USER No SMTP username
SMTP_PASS No SMTP password
SMTP_FROM No Sender address for outgoing email
NODE_ENV No Set to production in production

SMTP settings can alternatively be configured through the admin UI at Admin → Settings → Communication after first login — the environment variables are a convenience for scripted deployments.

Serving multiple domains

BETTER_AUTH_URL is always trusted and should point at your primary domain. If the same instance must also accept logins from additional domains (for example holtermeeting.de and holter-meeting.de alongside homee.rocks), list them in BETTER_AUTH_TRUSTED_ORIGINS:

BETTER_AUTH_TRUSTED_ORIGINS=https://homee.rocks,https://holtermeeting.de,https://holter-meeting.de

Set this on both the nextjs and bullmq-worker services. Unset, only BETTER_AUTH_URL is trusted.

Updating HoMeeSuite

Pull the new image and recreate the containers:

docker compose pull
docker compose up -d

Migrations run automatically on startup. No manual migration step is needed.

Persistent data

All state lives in named Docker volumes:

Volume Contents
postgres_data All application data — back this up
redis_data BullMQ job queues — safe to lose
uploads_data Event cover photos and file uploads

Back up postgres_data regularly with pg_dump:

docker compose exec postgres pg_dump -U homeesuite homeesuite > backup-$(date +%F).sql

Reverse proxy / TLS

The nextjs container listens on port 3000. Put a reverse proxy (nginx, Caddy, Traefik) in front of it for TLS termination. A minimal nginx snippet:

server {
    listen 443 ssl;
    server_name your-domain.example.com;

    ssl_certificate     /etc/letsencrypt/live/your-domain.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.example.com/privkey.pem;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    location / {
        proxy_pass         http://localhost:3000;
        proxy_set_header   Host $host;
        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;
    }
}

Health check endpoint

GET /api/health returns 200 OK when the app is ready. Use this for load balancer and monitoring probes.

Troubleshooting

Container exits immediately — check logs with docker compose logs nextjs. A missing BETTER_AUTH_SECRET or DATABASE_URL is the most common cause.

Database migration fails — the postgres container may not have been healthy yet. Run docker compose restart nextjs once the database is up.

Email not sending — configure SMTP under Admin → Settings → Communication and use the test-send button to verify delivery.

/setup redirects to login — a Superadmin already exists. Use the login page or reset credentials directly in the database if you are locked out.