Areas we serve

Self-Hosted GoCron: YAML Cron Jobs With a UI and SQLite Logs

Your backup script lives in git, but the schedule lives in someone's head and a root crontab nobody wants to edit through SSH. You add a cron UI, then realize you still need log history, per-job environment variables, and a way to run the job now without opening a terminal at 2 a.m.

GoCron (flohoss/gocron, ~625 GitHub stars, MIT, Go + Vue.js) is a self-hosted scheduler that keeps job definitions in YAML, runs them on standard cron expressions, and gives you a small web dashboard for manual runs and logs. State lives in SQLite. It is deliberately simpler than a distributed orchestrator: one process, one config file, commands executed with sh -c so pipes and redirects work naturally.

What you get

  • YAML jobs — name, cron, ordered commands, per-job envs, plus shared job_defaults for cron, timeout, retries, and pre/post hooks.
  • Live reload — edit config.yaml and the scheduler rebuilds without a container restart (listener and DB path changes still need a restart per upstream docs).
  • Web UI — trigger runs, read history, stream logs over SSE; optional sandboxed terminal with an allow-list (do not enable allow_all_commands on the internet).
  • Operational knobs — per-command timeouts and retries, fail-fast vs continue-on-error, timezone-aware schedules, run retention in SQLite.
  • Health hooks — HTTP callbacks on start, end, and failure (documented for Gatus push monitoring so silence means "job never ran").
  • Backup-friendly image — optional install of restic, borg, rclone, rsync, docker/podman at startup if you want backup jobs without custom Dockerfiles.
  • OIDC — optional login for UI and API; without it, anyone who can reach the port can control jobs, so TLS and auth matter on public hosts.

How it compares to other schedulers we have covered

Dagu wants YAML DAGs with dependencies and a heavier operations story. Cronicle and Cronmaster target multi-worker or host crontab editing. GoCron sits closer to "cron with git-friendly config and a UI": no DAG graph, no cluster, but clearer than raw crontab when non-shell teammates need to click Run and read output.

Important behavioral detail: GoCron is single-flight. While one job runs, another scheduled job is skipped, not queued. Missed runs while the container is down are not replayed. Parallel workloads mean multiple GoCron instances with separate configs, not one mega scheduler.

Why self-host?

Backup and maintenance commands often touch database dumps, object storage keys, and internal URLs. Keeping the scheduler and its SQLite history on your VPS avoids shipping that metadata to a SaaS cron vendor. MIT license, a single container, and config that can live in a private git repo fit homelabs, MSP nightly check scripts, and small teams who outgrew crontab but do not need Airflow.

Defaults run commands as root inside the published image unless you harden that. Mount only what each job needs, keep secrets in Docker secrets or --env-file, not plaintext in YAML, and put GoCron behind OIDC or a trusted network.

Quick start

docker run -it --rm \
  --name gocron \
  -p 8156:8156 \
  -v ./config/:/app/config/ \
  ghcr.io/flohoss/gocron:latest

First boot creates a starter config.yaml from the example. Open port 8156, add jobs, set time_zone to something sensible (e.g. America/Edmonton for Alberta ops). NixOS users get a packaged module on nixpkgs if that is already how you deploy services.

jobs:
  - name: 'Nightly restic'
    cron: '0 5 * * *'
    timeout: '2h'
    retries: 1
    envs:
      - key: RESTIC_REPOSITORY
        value: '/backups'
    commands:
      - restic backup /data
      - restic forget --keep-daily 7

Put Caddy or Nginx in front for HTTPS, configure trusted_proxies if you rate-limit by client IP, and disable proxy buffering on /api/events if live logs stutter.

Who it is for

Good fit: solo admins wrapping restic/borg/rsync; homelabs with a handful of recurring shell tasks; teams that want YAML in git plus a click-to-run UI; anyone pairing GoCron health hooks with Gatus or Apprise inside commands.

Skip it: if you need DAG dependencies and parallel steps in one run; if overlapping backup windows are normal (single-flight will drop schedules); if you want workers across many hosts without running one GoCron per box.

Hosting in Canada

GoCron is light. A basic CloudBox VPS can host the container, your config volume, and SQLite alongside the workloads it triggers. Back up db.sqlite with the same discipline as the jobs it runs. Canadian residency is about where that database and your backup credentials sit, not where cron thinks noon is, so set time_zone explicitly for local maintenance windows.

Bottom line

GoCron is cron that respects version control: readable YAML, honest failure semantics, and a UI that does not pretend to be a data platform. If your infrastructure fits in a page of shell commands and you want logs without SSH, it is a strong weekend deploy.

Talk with Swift Host for sizing a Canadian VPS, TLS, and backup scope around schedulers like GoCron. We are in St. Albert and actually answer the phone.

Tags:
  • GoCron
  • Cron
  • Scheduler
  • Self-Hosted
  • YAML

Need Help With Your Hosting?

Tell us about your application — we respond within 1 hour with honest recommendations.