Skip to content
cronpad
Get started / Self-host cronpad

Self-host cronpad

This tutorial runs cronpad on one machine with Docker Compose, configures GitHub sign-in, and creates a first job. For production hardening, read the production checklist afterwards.

Before you start

  • Docker with the Compose plugin.
  • A GitHub account (to create an OAuth app), or use development login for a local trial.

1. Get the Compose file

mkdir cronpad && cd cronpad
curl -fsSLO https://raw.githubusercontent.com/gowthamgts/cronpad/main/deploy/docker-compose.yml

It starts one container, cronpad (port 8080), with everything it stores in the cronpad-data volume. There is no database or queue server to run.

2. Configure sign-in

For a quick local trial, enable development login (never use this on a server reachable by others):

cat > .env <<'ENV'
CRONPAD_AUTH__DEV_LOGIN=true
ENV

For real use, create a GitHub OAuth app with callback URL http://localhost:8080/auth/github/callback and put its credentials in .env:

cat > .env <<'ENV'
CRONPAD_SERVER__PUBLIC_URL=http://localhost:8080
CRONPAD_AUTH__GITHUB__CLIENT_ID=Iv1.xxxxxxxx
CRONPAD_AUTH__GITHUB__CLIENT_SECRET=xxxxxxxx
ENV

Google works the same way. See Authentication.

Create a persistent encryption key before saving jobs, including with development login, and tell Compose to pass .env into the server:

printf 'CRONPAD_SECRETS__ENCRYPTION_KEY=%s\n' "$(openssl rand -base64 32)" >> .env
cat > docker-compose.override.yml <<'YAML'
services:
  cronpad:
    env_file: .env
YAML

Keep that encryption key when restarting or upgrading. See Secrets for rotation.

3. Start it

docker compose up -d
docker compose logs -f cronpad

Wait for the server started log line, then open http://localhost:8080. A new server opens on a setup page: sign in to create the first account, and you land on the dashboard at /. Sign-up then closes; see First sign-in to let others in.

4. Schedule a job

Create a webhook job in the dashboard at /jobs/new, using an HTTPS endpoint you control. The default Compose service disables the command sink unless you set CRONPAD_SINKS__COMMAND__ENABLED=true.

Or create it with the CLI after making an API key in Settings:

export CRONPAD_URL=http://localhost:8080
export CRONPAD_API_KEY=cp_…
cronpad jobs create --name report --schedule 'every day at 2am' --tz UTC \
  --url https://example.com/your-hook

To run a command job, set CRONPAD_SINKS__COMMAND__ENABLED=true (overriding the default Compose value), then install or mount an executable at /usr/local/bin/backup.sh inside the container. On that configured server, command creation is:

cronpad jobs create --name backup --schedule 'every day at 2am' --tz UTC \
  --command /usr/local/bin/backup.sh

--arg adds individual arguments without shell interpolation.

On self-hosted installs, jobs can run shell commands inside the cronpad container in addition to webhooks. See Commands.

5. Check health

curl -s localhost:8080/readyz
# {"dispatcher":"active","heartbeat":"…","queue":true,"sqlite_writable":true,"writer_backpressure":false}

Next steps