Self-hosted service
fccview/cronmaster avatar
fccview/cronmaster

cronmaster: A Web Interface for Cron Jobs, With Live Log Streaming

Cronjob management UI with human readable syntax, live logging and log history for your cronjobs.

1,394 stars39 forksTypeScriptAGPL-3.0

At a glance

What is it?
Cronmaster is a Next.js application that puts a browser interface in front of the host crontab, with human readable schedules, a script manager, optional job logging and server sent events for live output. It is designed to run as a privileged Docker container that edits crontab files directly, which is the point and also the risk.
Who is it for?
Cronmaster fits a homelab, a self-hosted box or a small server team that wants to see and edit schedules, run scripts and watch job output without opening a terminal over SSH, and it is the wrong tool for a shared production host where a privileged container with the Docker socket mounted and the host PID namespace is not an acceptable risk.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 19 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A Browser Interface Over the Host Crontab

Cronmaster is described as a cronjob management UI with human readable syntax, live logging and log history. It is a Next.js application written in TypeScript, and it puts a web interface in front of the scheduler on the machine it runs on.

The feature list gives the scope. There is a modern responsive interface with dark and light mode, a system information view showing uptime, memory, network, CPU and GPU, and cron job management where you can view, create and delete cron jobs with comments. There is a script manager for creating and deleting bash scripts to use within the cron jobs, which removes the usual dance of editing a file on the host from a second machine.

Job execution logging is optional and captures stdout, stderr, exit codes and timestamps, with automatic cleanup of the stored logs. Live updates come over server sent events, giving real-time job status and live log streaming for long-running jobs when logging is enabled.

The dependency list explains some of the choices: cron-parser and cronstrue for the schedule handling and the human readable rendering, systeminformation for the system panel, CodeMirror for the script editor, proper-lockfile for safe concurrent access, and next-intl and next-themes for localisation and the colour modes.

The Docker Compose File Is the Installation

The recommended path is Docker, and the README gives a minimal compose file that is worth reading line by line before you use it:

yaml
services:
  cronmaster:
    image: ghcr.io/fccview/cronmaster:latest
    container_name: cronmaster
    user: "root"
    ports:
      - "40123:3000"
    environment:
      - NODE_ENV=production
      - NEXT_PUBLIC_CLOCK_UPDATE_INTERVAL=30000
      - AUTH_PASSWORD=very_strong_password
      - HOST_CRONTAB_USER=root
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./scripts:/app/scripts
      - ./data:/app/data
      - ./snippets:/app/snippets

Two entries in that file carry the security weight. The Docker socket is mounted, which gives the container control over the Docker daemon, and the container runs as root with the host PID namespace and privileged mode set in the fuller example. The README states the requirement plainly: root user is required for cron operations and direct file access, and there is no way around this. If that is uncomfortable, the alternative given is to run the app locally with yarn install, yarn build and yarn start.

The compose file also maps port 40123 on the host to 3000 in the container, so the interface is at http://localhost:40123 after docker compose up --build, and the scripts, data and snippets directories are bind mounted so their contents survive a container replacement.

It Edits Crontab Files Directly, Not Through the crontab Command

The most important technical decision is stated in a note under the Docker instructions: the Docker implementation uses direct file access to read and write crontab files, ensuring real-time synchronization with the host system's cron jobs, and this approach bypasses the traditional crontab command limitations in containerized environments.

That is a reasonable engineering answer to a real problem. The crontab command operates on a per-user spool, so a container managing another user's crontab needs either the right user context or privileged access to the spool, and reading the spool back for display is awkward. Reading and writing the files directly gives the UI a live view of what the host will actually run, rather than a copy that can drift.

The consequence is that the container needs to run as root and needs to see the host's crontab location, which is why HOST_CRONTAB_USER is one of the environment variables in the compose file. The Dockerfile installs su-exec and docker-cli alongside curl, iputils, pciutils and util-linux, and the container is set up with a non-root nextjs user for the application itself.

The compose file also declares a health check against the health endpoint with a 30 second interval, a 10 second timeout, a 30 second start period and three retries, and the Dockerfile repeats that as a HEALTHCHECK instruction, which is a small sign that the project expects to be run as a long-lived service.

Job Execution Has Two Different Modes

The smart job execution feature describes a split that matters more than it first appears. Jobs with logging run in the background with live updates, and jobs without logging run synchronously with a five-minute timeout.

The reason is the delivery mechanism. Without logging enabled there is nowhere to stream output to, so the request has to wait for the job to finish, and the five-minute ceiling keeps a long-running command from holding a request open indefinitely. With logging enabled the job is started in the background, its output is written to the log store, and the browser receives it over server sent events as it is produced.

That is a good design for a long-running backup or a data import, where the interesting question is what the job printed rather than only whether it succeeded. The captured fields are stdout, stderr, exit codes and timestamps, and the log history is kept with automatic cleanup, so the storage grows on its own terms rather than needing a retention policy you configure.

The script manager is the other half of the workflow. Creating a bash script in the browser, in a CodeMirror editor with lint and search support, and then referencing it from a cron entry keeps the script and its schedule in the same place, which is the convenience that makes the tool pleasant for a homelab.

Password, OIDC and API Keys Are All Supported Together

Authentication is one of the stronger areas of the documentation, with separate how-to pages for the environment variables, the SSO setup, the API, the translations, the logging and the Docker options.

Password authentication is a single environment variable, AUTH_PASSWORD, and users are prompted for it before they reach the application. The password is hashed with bcryptjs, which is in the dependency list.

Single sign-on uses OIDC, and the README says it supports any OIDC provider, naming Authentik, Auth0, Keycloak, Okta, Google and Entra ID among them. The implementation uses the jose library for the token handling, and you can enable password and SSO authentication simultaneously, which is what most people actually want during a migration.

There is a full REST API for programmatic access to cron jobs and system information, with optional API key authentication for external integrations. That is the route to use if you want to trigger a job from a webhook receiver or a monitoring system rather than from the browser.

Localisation is also part of the project. Some languages are officially supported, and the translations live in a directory in the app, and you can create your own translations locally on your own machine, with the how-to page describing the process.

The Stack Behind the Interface

The package.json describes a fairly conventional modern Next.js application. The framework is Next 16 with React 19, styled with Tailwind CSS 3, and the scripts are the standard ones: next dev, next build and next start, with eslint for linting and vitest for tests. The Dockerfile builds on node:24-alpine in three stages, a dependency stage that installs from whichever lockfile is present, a builder stage that runs the build with telemetry disabled, and a runner stage that copies the standalone output, adds the system utilities and runs as the nextjs user.

Two details in the runner stage are worth noting. The application directories /app/scripts, /app/data and /app/snippets are created and owned by the nextjs user, which matches the bind mounts in the compose file, and the container runs with HOSTNAME set to 0.0.0.0 and PORT 3000, which is what lets the port mapping work.

The repository also carries a howto/ directory with the detailed documentation pages the README keeps linking to, an AGENTS.md and a CONTRIBUTING.md, a proxy.ts and an instrumentation.ts for Next.js, a tests/ directory with a vitest configuration, and a Dockerfile and docker-compose.yml at the root. The multi-architecture build is handled by the Docker setup, and the README explains that for ARM64 users the compose file needs the platform line uncommented as linux/arm64, while AMD64 users need no changes.

Where This Does and Does Not Belong

The honest framing of this project is that it is a convenience and visibility tool that runs with a high level of privilege, and that trade-off has to be made deliberately.

It belongs on a machine you administer, where the person deploying it already has root and the scheduled jobs are the owner's own scripts. A homelab, a build box, a personal server with a handful of cron jobs, a machine where the current workflow is SSH plus a text editor, all of these are cases where a browser interface is a clear improvement and the privilege level is already the status quo.

It does not belong on a shared production host where a compromise of the web application would be a compromise of the host. The container mounts the Docker socket, runs privileged, joins the host PID namespace and writes to the root crontab. Any of those on their own would be a finding in a security review, and together they are the reason the README is unapologetic about the root requirement rather than trying to work around it.

The licence is AGPL-3.0, which is a stronger obligation than MIT or Apache for a network service, and that is a deliberate choice for a project you would host yourself. The release history is active, with 2.4.0 on 2026-10-04, 2.3.2 on 2026-08-13 and 2.3.1 on 2026-05-27, and the last push was on 2026-10-04, so the project is being maintained rather than left in place.

Editorial conclusion

Cronmaster fits a homelab, a self-hosted box or a small server team that wants to see and edit schedules, run scripts and watch job output without opening a terminal over SSH, and it is the wrong tool for a shared production host where a privileged container with the Docker socket mounted and the host PID namespace is not an acceptable risk. Before deploying it, read the Docker notes, because the README is explicit that the root user is required for cron operations and direct file access and that there is no way around it, and check how your scheduled commands behave as root on the host, since a command that works as root on the host can still fail inside the container. The project is AGPL-3.0 licensed, the newest release is 2.4.0 from 2026-10-04, and the last push was on 2026-10-04.

Frequently asked questions

How do I run Cronmaster with Docker?

Create a docker-compose.yml using the configuration in the README, with the image ghcr.io/fccview/cronmaster:latest, the port mapping 40123:3000 and the AUTH_PASSWORD and HOST_CRONTAB_USER variables, then run `docker compose up --build` and open http://localhost:40123. The Docker socket and data volume mounts are required for proper functionality.

Does Cronmaster need to run as root?

Yes. The README states that the root user is required for cron operations and direct file access, and that there is no way around this. If you are not comfortable with that, the suggested alternative is to run the app locally with yarn install, yarn build and yarn start instead.

How does Cronmaster handle long-running jobs?

There are two modes. Jobs with logging enabled run in the background with live updates over server sent events, capturing stdout, stderr, exit codes and timestamps. Jobs without logging run synchronously with a five-minute timeout.

Can I use single sign-on with Cronmaster?

Yes, via OIDC. The README says it supports any OIDC provider, naming Authentik, Auth0, Keycloak, Okta, Google and Entra ID among them, and password and SSO authentication can be enabled at the same time. The full setup is in howto/SSO.md.

How do I install Cronmaster for local development?

Run `yarn install` and then `yarn dev`, and open http://localhost:3000. The production path is the Docker compose setup, which the README marks as the recommended one, with the full option list in howto/DOCKER.md.

Official sources

  1. fccview/cronmaster on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fccview-cronmaster.svg)](https://hysenlabs.com/projects/fccview-cronmaster)

Was this useful?