WebCalendar

How to Install WebCalendar with Docker Compose (Step-by-Step Guide)

WebCalendar is a free, open-source calendar application written in PHP. You can run it as a personal calendar, a shared calendar for a group or intranet, or a public event calendar. The fastest and cleanest way to get it running today is with Docker Compose — no fiddling with PHP versions, Apache modules, or database packages on your host.

This guide covers two paths:

  1. Quick start — clone the repo and bring the stack up with a single command. Best for trying WebCalendar or spinning up a dev instance.
  2. Production setup — a self-contained docker-compose.yml using the published Docker image, a persistent MariaDB volume, and environment-based configuration. Best for a server you’ll actually keep.

By the end you’ll have WebCalendar running at http://localhost:8080 with your data safely persisted.

Prerequisites

  • Docker Engine and the Docker Compose plugin (docker compose version should print v2.x). On older installs the command is the hyphenated docker-compose — both work here.
  • About 5 minutes.
  • A machine with a couple hundred MB of free RAM. WebCalendar is light.

WebCalendar 1.9.x requires PHP 8.2+ and a supported database (MySQL/MariaDB, PostgreSQL, or SQLite3). The container images bundle the right PHP for you, so you don’t need PHP installed on the host.


Method 1 — Quick start (clone + official Compose file)

The repository ships with a ready-to-run Compose file. This is the path documented in the project README, and it automatically loads the database schema for you.

git clone https://github.com/craigk5n/webcalendar.git
cd webcalendar
docker compose -f docker/docker-compose-php8.yml up -d

That’s it. Three things just happened:

  • A MariaDB container (webcalendar-db) started and, on first boot, loaded the WebCalendar schema from install/sql/tables-mysql.sql.
  • A PHP 8 + Apache container started serving WebCalendar.
  • Port 8080 on your host was mapped to Apache’s port 80 in the container.

Open http://localhost:8080 in your browser. On first run WebCalendar’s setup wizard writes its configuration to includes/settings.php, then hands you off to the login page.

Log in with the default admin account — admin / admin — and change the password immediately under Preferences (or the admin account’s settings). This is the single most important step; a self-hosted calendar left on the default password is an open door.

To watch the logs or stop the stack:

docker compose -f docker/docker-compose-php8.yml logs -f
docker compose -f docker/docker-compose-php8.yml down      # stop (keeps data)

The MariaDB data lives in a named Docker volume (mysql-data), so down and up won’t lose your events. Only down -v deletes the volume.


Method 2 — Production setup (published image, no clone)

For a server you intend to keep, you don’t need the source tree at all. Pull the published image, k5nus/webcalendar, and configure everything through environment variables so there’s no interactive wizard and no writable settings.php to manage.

Create an empty directory and two files.

1. Grab the schema (loaded into MariaDB on first boot):

curl -O https://raw.githubusercontent.com/craigk5n/webcalendar/master/install/sql/tables-mysql.sql

2. Create docker-compose.yml:

services:
  db:
    image: mariadb:11
    container_name: webcalendar-db
    environment:
      MARIADB_DATABASE: webcalendar
      MARIADB_USER: webcalendar
      MARIADB_PASSWORD: change-me-to-a-strong-password
      MARIADB_ROOT_PASSWORD: change-me-too
    volumes:
      - db-data:/var/lib/mysql
      - ./tables-mysql.sql:/docker-entrypoint-initdb.d/01-tables.sql:ro
    restart: unless-stopped

  webcalendar:
    image: k5nus/webcalendar:latest      # or pin a version, e.g. k5nus/webcalendar:1.9.16
    container_name: webcalendar
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      WEBCALENDAR_USE_ENV: "true"
      WEBCALENDAR_DB_TYPE: mysqli
      WEBCALENDAR_DB_HOST: db
      WEBCALENDAR_DB_DATABASE: webcalendar
      WEBCALENDAR_DB_LOGIN: webcalendar
      WEBCALENDAR_DB_PASSWORD: change-me-to-a-strong-password   # must match MARIADB_PASSWORD
      WEBCALENDAR_DB_PERSISTENT: "true"
      WEBCALENDAR_MODE: prod
    restart: unless-stopped

volumes:
  db-data:

When WEBCALENDAR_USE_ENV is true, WebCalendar reads its database connection from these variables and ignores includes/settings.php entirely — which means no writable config file inside the container and no wizard step. Pin the image to a version tag (like 1.9.16) in production so an unexpected latest update never surprises you.

3. Bring it up:

docker compose up -d

Browse to http://localhost:8080 and log in as admin / admin, then change the password.

Optionally protecting the installer

WebCalendar can guard its setup/settings routines behind an install password. Generate an MD5 hash of your chosen password and pass it in:

php -r "echo md5('YourInstallPassword');"

Add the result as WEBCALENDAR_INSTALL_PASSWORD to the webcalendar service’s environment.


Where your data lives (and how to back it up)

Everything that matters — users, events, categories, preferences — is in the database, which is stored in the db-data Docker volume. Backing WebCalendar up is therefore just a MariaDB dump:

# Backup
docker compose exec db 
  mariadb-dump -u webcalendar -p'change-me-to-a-strong-password' webcalendar 
  > webcalendar-backup-$(date +%F).sql

# Restore
docker compose exec -T db 
  mariadb -u webcalendar -p'change-me-to-a-strong-password' webcalendar 
  < webcalendar-backup-2026-07-08.sql

Store those dumps off the server (S3, another host, etc.). Automate it with a nightly cron job and you have a real disaster-recovery story.

Putting it behind a domain with HTTPS

Method 1 and 2 both expose plain HTTP on port 8080 — fine for localhost, not for the public internet. In production you’ll want a reverse proxy (Nginx, Caddy, or Traefik) terminating TLS in front of the container and forwarding to webcalendar:80. That’s a post of its own — Run WebCalendar Behind a Reverse Proxy with HTTPS — but the short version: don’t publish port 8080 to the world; bind it to 127.0.0.1:8080 and let your proxy handle 443.

Upgrading

With a pinned image tag, upgrading is: bump the tag, pull, and recreate the app container.

# edit docker-compose.yml: k5nus/webcalendar:1.9.16 -> :1.9.17
docker compose pull webcalendar
docker compose up -d webcalendar

WebCalendar applies any needed database updates on the next load. Take a database backup first (see above) — always, every time.

Troubleshooting

  • Blank page or “cannot connect to database”: the app started before MariaDB finished initializing. Give it a few seconds and reload, or docker compose restart webcalendar. Confirm WEBCALENDAR_DB_PASSWORD exactly matches MARIADB_PASSWORD.
  • Login fails with admin/admin: the schema didn’t load. In Method 2, make sure tables-mysql.sql was present before the first up — the init script only runs on an empty data volume. Run docker compose down -v && docker compose up -d to re-initialize (this wipes data).
  • Port 8080 already in use: change the host side of the mapping, e.g. - "9090:80".
  • Check the logs: docker compose logs webcalendar and docker compose logs db are your first stop for anything.

Next steps

Running WebCalendar in Docker in production? I’d love to hear how — leave a comment with your setup.

Leave a Reply

Your email address will not be published. Required fields are marked *