pg timetable
Overview
pg_timetable is an advanced, database-driven job scheduler for PostgreSQL from CYBERTEC. Unlike cron, it keeps every schedule, task and execution log inside PostgreSQL. You define chains of SQL, shell (PROGRAM) and BUILTIN tasks, schedule them with full cron syntax or intervals, and pg_timetable executes them transactionally and records every run in the database.
This guide covers deploying pg_timetable on Ubuntu 24.04 on Azure with the SecureAnyCloud image from the Azure Marketplace. The image installs a local PostgreSQL 16 instance (from the official PostgreSQL PGDG repository) and connects pg_timetable to it, so the appliance is useful the moment it boots. You can watch a real scheduled job fire immediately, then define your own.
What you get:
- pg_timetable v7.0.0 (the pinned upstream Go binary) running as the
pg-timetable.servicesystemd daemon - A bundled local PostgreSQL 16 instance that backs the scheduler and listens on
127.0.0.1only, with no public database port - Only TCP 22 open in the image's Network Security Group, so there is no public database port to attack
- A scheduler that reaches PostgreSQL entirely over the loopback interface as an unprivileged
schedulerrole - A seeded demo chain that proves the scheduler works. On first boot the scheduler bootstraps its
timetableschema, and the chain runs a per-minute SQL task that appends a timestamped row topublic.sac_demo, plus a per-minuteBUILTINLog task - Full cron-style and interval scheduling, with schedules, tasks and execution history stored entirely inside PostgreSQL
- No credential baked into the image. On first boot the PostgreSQL superuser and the
schedulerapplication role each receive an independent random password - The scheduler's connection string written to
/etc/pg_timetable/pg_timetable.env(mode0600, read by systemd), and a root-only summary written to/root/pg-timetable-credentials.txt - A PostgreSQL data directory that is reset when the image is built, so every deployed VM starts from a clean cluster with fresh credentials
- A prep-only first boot that creates the credentials and seeds the demo chain, then hands off to a sentinel-gated daemon, so the scheduler never starts with a default credential
- Unattended security upgrades left enabled, so the appliance keeps receiving patches
Prerequisites
You need an active Azure subscription, an SSH public key, and a VNet with a subnet in the target region. You also need a subscription to the pg_timetable listing on the Azure Marketplace.
Configure a Network Security Group (NSG) rule that allows TCP 22 (admin) from your management network. This appliance exposes no database port.
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for the demo and light scheduling workloads. For busier schedules or larger backing databases, use Standard_D2s_v5 or larger.
Deploy from the Azure Portal
Search the Azure Marketplace for pg_timetable, select the SecureAnyCloud publisher, and click Create.
Configure the Network Security Group to allow TCP 22 for administration from your management network. No inbound database port is required, because the bundled PostgreSQL is loopback only.
Deploy from the Azure CLI
RG="scheduler-prod"; LOCATION="eastus"; VM_NAME="pgtt1" IMAGE_URN="sac1647283583153:pg-timetable-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:pg-timetable-ubuntu-24-04:default:latest
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$IMAGE_URN" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
# Open only the admin port on the VM's NSG:
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1001First boot
On first boot, the image starts PostgreSQL on the loopback interface and generates a per-VM password for the PostgreSQL superuser and the scheduler role. It creates the timetable database, bootstraps the pg_timetable schema and seeds the demo chain. It then writes /root/pg-timetable-credentials.txt and starts the scheduler daemon. This completes within a minute.
SSH in as azureuser and read the details:
sudo cat /root/pg-timetable-credentials.txtConfirm the scheduler and its database are healthy
The scheduler daemon runs as pg-timetable.service, and the bundled PostgreSQL is loopback only. Confirm that both are active and that PostgreSQL is bound to 127.0.0.1 with no public database port.
systemctl is-active postgresql.service pg-timetable.service ss -tlnH | grep 5432See the installed version and the registered chains
pg_timetable stores every chain in the timetable.chain table. The appliance ships v7.0.0 and two seeded demo chains, both live and scheduled every minute (* * * * *). Print the version and list the chains:
/usr/local/bin/pg_timetable --version sudo -u postgres psql -d timetable -c \
'SELECT chain_id, chain_name, run_at AS schedule, live FROM timetable.chain ORDER BY chain_id;'Watch the scheduled chain actually run
The sac_demo_tick chain runs an SQL task every minute that appends a timestamped row to public.sac_demo. Query the table a few times. New rows appear, each with a real, minute-spaced timestamp, which shows that the scheduler is firing.
sudo -u postgres psql -d timetable -c \
'SELECT id, message, ran_at FROM public.sac_demo ORDER BY ran_at DESC LIMIT 8;'Inspect the execution log
pg_timetable records every task it runs in timetable.execution_log, including the start and finish time and the return code (0 = success). This is your audit trail for scheduled work. Query the most recent entries:
sudo -u postgres psql -d timetable -c \
'SELECT chain_id, task_id, last_run, finished, returncode FROM timetable.execution_log ORDER BY last_run DESC LIMIT 8;'Define your own scheduled job
Add your own jobs with the timetable.add_job() helper. The connection string for the scheduler role is in /etc/pg_timetable/pg_timetable.env. The simplest way to run SQL against the scheduler database as an admin is over the local peer connection as the postgres user.
This example runs a VACUUM every night at 02:00:
sudo -u postgres psql -d timetable <<'SQL' SELECT timetable.add_job( job_name => 'nightly_vacuum', job_schedule => '0 2 * * *', job_command => 'VACUUM', job_kind => 'SQL'::timetable.command_kind ); SQLChains can combine SQL, shell (PROGRAM) and BUILTIN tasks. They run steps in sequence with per-task error handling, and they support interval schedules such as @every 30 minutes as well as cron syntax. For the full task model, see the CYBERTEC documentation and the bundled examples under the release samples/ directory.
Manage the scheduler daemon
The daemon reads its connection string from /etc/pg_timetable/pg_timetable.env and runs as the unprivileged pgtt user. Manage it with standard systemd commands:
systemctl status pg-timetable.service journalctl -u pg-timetable.service -n 50 --no-pager sudo systemctl restart pg-timetable.serviceSecurity recommendations
Keep the database private. The bundled PostgreSQL is loopback only, and no database port is exposed. If you connect additional databases, reach them over a private VNet, never a public address.
Restrict the NSG. Allow TCP 22 only from your management network.
Guard what your chains can do. PROGRAM (shell) tasks run commands on the host. Review any chains you add, and consider the --no-program-tasks daemon flag if you only need SQL and built-in tasks.
Protect the scheduler database. Schedules, task definitions and execution history live in the timetable database. Restrict access to the VM, and back up the database as you would any production PostgreSQL database.
Keep the OS and PostgreSQL patched. Unattended security upgrades remain enabled on the running VM.
Support and Licensing
pg_timetable is developed by CYBERTEC PostgreSQL International GmbH and distributed under the PostgreSQL License (a permissive, BSD-style license). This SecureAnyCloud image ships the unmodified upstream pg_timetable v7.0.0 binary alongside the PGDG PostgreSQL 16 packages.
SecureAnyCloud provides the packaging, the secure-by-default, loopback-only configuration, the prep-only first-boot credential generation, the sentinel-gated daemon, and 24/7 support with a guaranteed 24-hour response SLA.
SecureAnyCloud is not affiliated with or endorsed by CYBERTEC. pg_timetable and PostgreSQL are marks of their respective owners and are used here only to identify the software.
Deploy on Azure
Find pg_timetable on Ubuntu 24.04 LTS on the Azure Marketplace, published by SecureAnyCloud. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email sales@secureanycloud.com for deployment help, configuration questions, or licensing enquiries.
Deploy on Azure
Launch pg_timetable PostgreSQL Job Scheduler on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com