Skip to content

Deploy to a server

This guide sets up Playdex on one Linux server (a small VPS is enough) with automatic HTTPS from Caddy.

You need:

  • A server with Docker and Git
  • Two DNS names pointing at the server, e.g. playdex.example.com and admin.playdex.example.com
  • Ports 80 and 443 open

Fill in the form. The files below update as you type. Everything is generated in your browser; secrets never leave this page.

Domains

By default the API lives at https://<web domain>/api/, so no CORS setup is needed.

Secrets

Generated locally with crypto.getRandomValues. Nothing on this page leaves your browser.

First administrator

Emails are case-sensitive at login. The password is bcrypt-hashed in your browser.

Optional features

  1. Clone Playdex on the server and add your files

    Terminal window
    git clone https://github.com/ivankaizer/playdex.git
    cd playdex

    Save docker-compose.prod.yml, .env and Caddyfile from the builder into this folder. Keep .env private; it’s already in .gitignore.

  2. Build and start

    Terminal window
    docker compose -f docker-compose.prod.yml up -d --build

    On start, the API applies database migrations, then reports healthy. Admin waits for the API before it starts.

  3. Check it’s healthy

    Terminal window
    curl -s https://playdex.example.com/api/ # → "Ok"
    docker compose -f docker-compose.prod.yml ps # api should be (healthy)
  4. Create your admin account

    Playdex has no public sign-up, so every account is created by an operator. Save create-admin.sql from the builder and run:

    Terminal window
    docker compose -f docker-compose.prod.yml exec -T db \
    psql -U playdex -d playdex < create-admin.sql

    Sign in at https://admin.playdex.example.com. The same email and password also work in the Web app.

  5. Invite people. See Users & admins.

Terminal window
git pull
docker compose -f docker-compose.prod.yml up -d --build

Migrations run automatically when the new API starts. They’re serialized with a Postgres advisory lock, so running several API replicas is safe. Admin never migrates the database. That’s why it waits for a healthy API.

Rolling back means checking out the previous commit and rebuilding. Migrations aren’t reversed automatically, so read the release’s changes before going back across a schema change.

All state is in Postgres (plus Apprise’s chat config, which re-creates itself):

Terminal window
docker compose -f docker-compose.prod.yml exec -T db pg_dump -U playdex playdex | gzip > playdex-$(date +%F).sql.gz

Each app ships a Dockerfile (src/Api, src/Web, src/Admin), so any container platform works. Mind these details:

  • API: set ASPNETCORE_URLS=http://+:3000. The image health-checks port 3000 but doesn’t set it itself. Health endpoints: /health/live, /health/ready (database + migrations).
  • Web: nginx on port 5056. It calls <its own origin>/api/ unless you set PLAYDEX_API_URL (ending in /api/). It doesn’t proxy /api itself, so your ingress must.
  • Admin: port 3100, needs only DATABASE_URL. Health: /health/live, /health/ready. Blazor Server uses WebSockets, so make sure your proxy allows them.
  • Behind a proxy: set ASPNETCORE_FORWARDEDHEADERS_ENABLED=true on API and Admin.
  • Least privilege: in production, give Admin its own Postgres role with access to app tables only, no DDL. The API role should be the only one that owns the schema.