Install on a server

Jigsaw targets fresh or dedicated Ubuntu or Debian machines with public hostnames. The installer configures Docker, clones the app to /opt/jigsaw by default, writes secrets, pulls images from GitHub Container Registry, and starts the stack.

Prerequisites

Requirement Notes
OS Ubuntu 22.04+ or Debian 12+. Other distros are not tested by the install script.
Hardware At least 2 GB RAM and enough disk for Docker images, PostgreSQL data, and site files (plan for growth).
Network Public IPv4 (or correct DNS/routing for your setup). Ports 80 and 443 must reach the host for HTTP-01 TLS.
Domain A registered domain you control. You will point DNS at this server before or during install.
Access SSH with sudo. The installer must run as root (use sudo).
Docker Not required beforehand — the script installs Docker Engine and the Compose plugin if missing.
Firewall: Allow inbound TCP 22 (SSH), 80, and 443. If you use ufw: ufw allow OpenSSH && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable

DNS before you run the installer

Create A records for the panel hostname, Keycloak, and Traefik dashboard. All three should point to the same public IP as your server (the installer checks public DNS against your detected public IP).

Host Type Value
panel.example.com A Your server's public IP
auth.panel.example.com A Same IP
traefik.panel.example.com A Same IP

Replace panel.example.com with the real FQDN you will enter when prompted (for example panel.yourdomain.com). Keycloak is always at auth.<PANEL_DOMAIN> and the Traefik UI at traefik.<PANEL_DOMAIN>.

Each customer site you create will need its own DNS record later (typically an A record to the same server).

Staging / private DNS: If public DNS is wrong or unavailable, you can skip strict checks with SKIP_DNS_CHECK=1 sudo ./install.sh — only do this when you understand the TLS implications.

One-line install

Download and run the official installer from the main branch (review the script on GitHub first if you prefer):

curl -fsSL https://raw.githubusercontent.com/03c/jigsaw/main/install.sh | sudo bash

Equivalent steps (explicit temp file, same effect):

curl -fsSL https://raw.githubusercontent.com/03c/jigsaw/main/install.sh -o /tmp/jigsaw-install.sh \
  && chmod +x /tmp/jigsaw-install.sh \
  && sudo /tmp/jigsaw-install.sh

If you already cloned the repository (for example to /opt/jigsaw), run the script from that directory:

cd /opt/jigsaw && sudo ./install.sh

What the installer does

  1. Installs Docker Engine and Compose if needed (APT on Debian/Ubuntu).
  2. Clones or updates the repo (default /opt/jigsaw).
  3. Prompts for panel domain, Let's Encrypt email, admin email, and Keycloak admin password.
  4. Generates or preserves secrets (POSTGRES_PASSWORD, SESSION_SECRET, OIDC and OAuth2 proxy secrets).
  5. Validates DNS for the panel and auth.<domain> when possible.
  6. Patches keycloak/jigsaw-realm.json with your domain and credentials.
  7. Pulls panel, PHP, and WordPress site images from ghcr.io/03c/jigsaw/ (builds locally if pull fails).
  8. Runs docker compose up -d, waits for PostgreSQL and Keycloak, updates OIDC redirect URIs, runs npm run db:push in the panel container.
  9. Waits until HTTPS responds for the panel and auth hostnames.

After install

  1. Open https://<PANEL_DOMAIN> — you will be redirected to Keycloak.
  2. Sign in with username admin and the Keycloak admin password you set, or use Register to create a new account (new users get the user role and can create sites up to the configured limit).
  3. Manage users and realm security settings at https://auth.<PANEL_DOMAIN> (Keycloak admin console).
  4. Open the Traefik dashboard at https://traefik.<PANEL_DOMAIN> (OAuth2 Proxy + Keycloak).

Sign up, DNS, and WordPress

Self-service sign-up is enabled in the default Keycloak realm so visitors can register without the admin console. To require invitations only, disable registration in Keycloak: Realm settings → Login → User registration.

Per-site DNS: before creating a site for blog.example.com, add an A record for that hostname to your server's public IP (same IP as the panel). Traefik issues TLS certificates per hostname once DNS resolves correctly.

WordPress (MVP flow):

  1. In the panel, go to Create site, enter a site name and domain.
  2. Keep Create database and Install WordPress checked (defaults).
  3. The panel provisions MariaDB, copies WordPress core from the WordPress site Docker image into your site folder, writes wp-config.php, then starts the jigsaw-wordpress web container (same Nginx + PHP stack as generic sites, with baked core in the image).
  4. Open https://your-domain and complete WordPress's web installer (title, admin user).

New Keycloak accounts use verifyEmail=false in the imported realm so users can sign in immediately. Turn on email verification in Keycloak if your deployment needs it.

Upgrading

cd /opt/jigsaw
git pull
docker compose pull
docker compose exec jigsaw npm run db:push
docker compose up -d

Rerunning sudo ./install.sh is also supported; it keeps existing .env secrets when present.

Manual install (advanced)

See the repository README — Manual install for cloning, hand-written .env, realm patching, image pulls, and docker compose up.