Developer Tools Azure

Cronmaster on Ubuntu 24.04 on Azure User Guide

| Product: Cronmaster on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Cronmaster on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Cronmaster is an open source, self hosted web interface for managing the cron jobs on a server. Instead of hand editing crontab text over SSH, you create, edit, pause, resume and run scheduled jobs from a browser, using a human readable schedule builder, with live job output and a searchable history of every run.

The image builds the pinned Cronmaster v2.3.1 release from source (recorded in /opt/cronmaster/VERSION). Cronmaster is a Next.js application that runs on Node.js 22 LTS under systemd and binds to loopback only (127.0.0.1:3000). nginx is the sole network facing surface and terminates TLS on port 443, reverse proxying to Cronmaster. Port 80 redirects to HTTPS.

Secure by default. Cronmaster manages the system crontab, so leaving it open would let anyone who can reach it schedule or run arbitrary commands on your server. This image turns authentication on and generates a unique administrator password on each virtual machine's first boot, written to a root only file. There are no shared or default credentials, nothing is baked into the image, and the service refuses to start without a password, so the open no authentication mode can never ship.

Manages the system crontab. Cronmaster reads and writes the host's cron jobs directly and runs with the privileges required to do so. Adding a job in the interface writes it straight to the real crontab, and the system cron daemon runs it. Because a cron management tool grants command execution to anyone who signs in, treat the admin password as highly sensitive and restrict who can reach the service.

What is included:

  • The pinned Cronmaster v2.3.1 release, built from source on Node.js 22 LTS and run under systemd

  • Cronmaster bound to loopback only (127.0.0.1:3000); it is never network exposed directly

  • nginx terminating TLS on :443 and reverse proxying to Cronmaster, with HSTS and sensible security headers

  • Port :80 returns a 301 redirect to HTTPS for every path except an unauthenticated /healthz endpoint (HTTP 200) for load balancer probes

  • Authentication on by default with a unique admin password generated per VM on first boot, written to a root only file

  • The system cron daemon installed and enabled, so scheduled jobs actually run

  • A self signed TLS certificate regenerated per VM on first boot (its Subject Alternative Names include the VM IP, hostname and 127.0.0.1); replace it with your own CA signed certificate for production

  • A built in self test at /usr/local/bin/cronmaster-selftest that proves the authentication and the host crontab integration end to end over TLS

  • Ubuntu 24.04 LTS base with the latest security patches applied at build time

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with a guaranteed 24 hour response SLA

Prerequisites

  • An Azure subscription with permission to deploy virtual machines

  • An SSH key pair for administrative access to the VM as the azureuser account

  • A Network Security Group allowing inbound TCP 443 (HTTPS) and 80 (redirect) from the networks that should reach the service, and 22 (SSH) from your management network only

  • A recommended size of Standard_B2s or larger

Step 1: Deploy from the Azure Portal

  1. Locate the Cronmaster on Ubuntu 24.04 LTS image in the Azure Marketplace and select Create.

  2. Choose your subscription, resource group and region.

  3. Select a VM size (Standard_B2s or larger) and provide your SSH public key for the azureuser account.

  4. On the Networking tab, allow inbound 443 and 80 from your users, and restrict 22 to your management network.

  5. Review and create. When the VM is running, browse to https://<your-public-ip>/.

Step 2: Deploy from the Azure CLI

Deploy the image from the command line, restricting SSH to your management network. Replace the placeholder values with your own before running:

az vm create \
  --resource-group my-resource-group \
  --name cronmaster \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard

# Allow the web UI from your users and SSH from your management network only
az vm open-port --resource-group my-resource-group --name cronmaster --port 443 --priority 1001
az network nsg rule create --resource-group my-resource-group --nsg-name cronmasterNSG \
  --name allow-ssh --priority 1002 --destination-port-ranges 22 \
  --source-address-prefixes <your-mgmt-cidr> --access Allow --protocol Tcp

When the VM is running, browse to https://<public-ip>/.

Step 3: Retrieve your per instance admin password

Authentication is on by default. Each VM generates its own admin password on first boot, written to a root only file. Read it over SSH:

ssh azureuser@<vm-ip> 'sudo cat /root/cronmaster-credentials.txt'

The file contains the CRONMASTER_PASS and CRONMASTER_URL for this specific VM. Cronmaster uses a single admin password and no username. Keep it secret. The password lives only in this root only file and in the service environment file, never baked into the image.

Step 4: Sign in to the web interface

Browse to https://<vm-ip>/. Because the certificate is self signed per VM, your browser will show a certificate warning the first time; accept it to proceed (or install the per VM certificate, or place a CA signed certificate in front, as covered in Step 11). Cronmaster presents a password prompt; enter the CRONMASTER_PASS value from Step 3.

The Cronmaster sign in screen served over TLS, showing a lock icon, a Welcome to Cronmaster heading, a single Enter password field and a Sign In button, with the version noted as 2.3.1

Step 5: The dashboard

After signing in, Cronmaster presents the dashboard. The left panel shows live system information (status, uptime, memory, CPU and load). The main panel lists every scheduled task with its raw cron expression, its command, a plain English translation of the schedule, and the user it runs as, along with a New Task button.

The Cronmaster dashboard after signing in, showing System Status Optimal with uptime, memory and CPU metrics on the left, and a Scheduled Tasks list of three cron jobs on the right including a pg_backup.sh job at 0 2 star star star translated to At 02:00 AM every day, and a certbot renew job translated to Every 15 minutes

Step 6: Create a cron job

Click New Task to open the create form. Choose the user the job runs as, enter the schedule, and pick a task type of either a Custom Command (a single command line) or a Saved Script from the library. Enter the command to run and an optional description. Saving the task writes it straight to the real crontab, and the system cron daemon runs it on schedule.

The Cronmaster Create New Scheduled Task form, showing a User selector set to root, a Schedule field with a picker, a Quick Patterns dropdown, a Task Type choice of Custom Command or Saved Script, and a Command input

Step 7: Build schedules with human readable syntax

You do not have to remember cron field order. Open Quick Patterns in the task form to pick from common intervals, each labelled in plain English, or search for one. Cronmaster fills in the matching cron expression for you, and the dashboard translates every job's schedule back into a sentence such as At 02:00 AM, every day so a schedule is never a mystery.

The Cronmaster Quick Patterns picker expanded in the task form, showing a search box and a list of common intervals such as star star star star star Runs every minute of every hour, slash 5 Runs every 5 minutes, slash 15 Runs every 15 minutes, 0 star Runs at the start of every hour and 0 slash 2 Runs every 2 hours

Step 8: Live job output and log history

Each job on the dashboard can be run on demand and its output streamed live in the interface, and Cronmaster keeps a searchable history of previous runs with their exit status, so you can see at a glance which jobs succeeded or failed and read the captured output of any run. Log retention is configurable through the service environment. You can also confirm what reaches the real system crontab directly from the shell:

sudo crontab -l -u root 2>/dev/null | head -20 || echo "(no jobs scheduled yet — add one in the web UI)"

Step 9: Verify the deployment

SSH to the VM as azureuser and confirm the services are running and Cronmaster is bound to loopback only:

systemctl is-active cronmaster nginx cron
sudo ss -tlnp | grep -E ':3000|:443 |:80 ' | sed 's/users:.*//'

All three services report active, and Cronmaster listens on 127.0.0.1:3000 only. nginx is the only component exposed on :80 and :443.

systemctl reports cronmaster, nginx and cron all active, and ss shows cronmaster bound to 127.0.0.1:3000 loopback only with nginx listening on 0.0.0.0:80 and 0.0.0.0:443

Run the built in self test. It reads this VM's password and proves the full round trip over TLS: an unauthenticated request is refused, a password login succeeds and the UI renders, and a job seeded into the system crontab is surfaced by the application, proving the host crontab integration:

sudo /usr/local/bin/cronmaster-selftest

The cronmaster-selftest output reporting OK: unauthenticated request returned 401, password login and authenticated request returned 200, the UI rendered, and the host root crontab read integration was proven over TLS

Step 10: TLS and the per instance certificate

nginx terminates TLS on port 443 and redirects plain HTTP on port 80 to HTTPS. Confirm the redirect, that an unauthenticated request is refused, and that a request carrying a valid session succeeds:

curl -s -o /dev/null -w 'port 80 -> HTTP %{http_code}\n' http://127.0.0.1/
curl -sk -o /dev/null -w 'unauthenticated -> HTTP %{http_code}\n' https://127.0.0.1/api/cronjobs
P=$(sudo grep '^AUTH_PASSWORD=' /etc/cronmaster/cronmaster.env | cut -d= -f2-)
J=$(mktemp)
curl -sk -c "$J" -o /dev/null -H 'Content-Type: application/json' --data "{\"password\":\"$P\"}" https://127.0.0.1/api/auth/login
curl -sk -o /dev/null -w 'authenticated -> HTTP %{http_code}\n' -b "$J" https://127.0.0.1/api/cronjobs
rm -f "$J"

Port 80 returns 301, an unauthenticated request returns 401, and an authenticated request returns 200. The self signed certificate is regenerated per VM on first boot, with the VM IP and hostname in its Subject Alternative Names:

curl shows port 80 returning a 301 redirect, an unauthenticated request returning 401 and an authenticated request returning 200, and openssl printing the per VM self signed certificate subject and Subject Alternative Names including the VM IP and hostname

Step 11: Version and the credential note

The baked version and this VM's credential summary are recorded on the VM. The password line is redacted below; read the full value from the root only file in Step 3:

cat /opt/cronmaster/VERSION
sudo sed 's/^CRONMASTER_PASS=.*/CRONMASTER_PASS=<redacted per-VM secret>/' /root/cronmaster-credentials.txt | grep -E '^CRONMASTER_'

The /opt/cronmaster/VERSION file showing the baked Cronmaster, Node.js and Next.js versions, and the per VM cronmaster-credentials.txt showing the URL with the password redacted

Step 12: Replace the certificate for production

The per VM certificate is self signed, so browsers warn on first use. For a public deployment, put a real certificate in front. The simplest path is to point a DNS name at the VM and obtain a free certificate with Certbot:

# Point https://<your-domain> at this VM first, then:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

Alternatively, terminate TLS at an Azure Application Gateway or a load balancer in front of the VM and forward to port 443.

Step 13: Configuration and rotating the password

  • Service and environment. The service definition is at /etc/systemd/system/cronmaster.service, and its environment (the per VM AUTH_PASSWORD and other settings) is in /etc/cronmaster/cronmaster.env.

  • Rotate the password by editing AUTH_PASSWORD in /etc/cronmaster/cronmaster.env (use a strong value of at least 16 characters — the service refuses to start with a shorter one) and running sudo systemctl restart cronmaster.

  • Which users' crontabs are managed is controlled by the HOST_CRONTAB_USER setting (the system root crontab by default). Adjust it in the unit if you want Cronmaster to manage a different user's cron jobs.

  • Optional single sign on. Cronmaster also supports OIDC single sign on with providers such as Keycloak, Authentik and Auth0; see the upstream documentation to configure SSO_MODE and the OIDC_* settings if you prefer SSO to the built in password.

Security notes

  • No default login. Authentication is on by default and a unique admin password is generated on each VM's first boot into a root only file and the service environment file. The service refuses to start without one.

  • Loopback only application. Cronmaster binds to 127.0.0.1:3000 and is only reachable through the nginx TLS reverse proxy on :443. Keep it that way and let nginx (or a load balancer) be the sole network facing surface.

  • It manages the system crontab. Cronmaster reads and writes the host's cron jobs and runs with the privileges required to do so. A cron management tool grants command execution to anyone who signs in, so treat the password as highly sensitive and restrict who can reach the service.

  • Restrict access. Allow 443 only from the networks that need it, keep 22 restricted to your management network, and replace the self signed certificate with a CA signed one for production.

  • HTTPS is load bearing. A cron management interface over plaintext HTTP would expose the login password and let anyone schedule commands. Always reach it over TLS.

Support

This image is backed by 24/7 cloudimg support with a guaranteed 24 hour response SLA. Contact support@cloudimg.co.uk for assistance. Cronmaster is open source software distributed under the GNU Affero General Public License v3.0 (AGPL-3.0) and is free; the cloudimg charge covers packaging, hardening, security patching, image maintenance and support.