Easy!Appointments
Easy!Appointments lets customers book time slots with a provider. Two containers — PHP with Apache, and MariaDB. No build step and no Node.js.
Last run on a host 9 Nov 2026 · data restored from a backup
Pinned at 1.6.1 (released 19 Oct 2026) · the newest upstream release
In the upstream images: 3 CRITICAL · 80 HIGH with a published fix — per image
To try it: Docker, nothing else. See Try it locally.
To deploy it behind the proxy: Traefik running and a domain.
Try it locally
Section titled “Try it locally”On your own machine, with no proxy, domain or certificate. From apps/easyappointments/:
cp .env.local.example .env.local
# The secrets ship empty; generate the ones this stack needs{ echo "DB_PASSWORD=$(openssl rand -base64 32 | tr -d '\n')" echo "DB_ROOT_PASSWORD=$(openssl rand -base64 32 | tr -d '\n')"} >> .env.local
mkdir -p volumes/local/mysql volumes/local/storagesudo chown -R 33:33 volumes/local/storage
docker compose -f docker-compose.local.yml --env-file .env.local up -dThen open http://localhost:8080. Stop it again with the same command and down.
Installation
Section titled “Installation”From apps/easyappointments/:
-
Copy the environment file and set
APP_TRAEFIK_HOSTandTZ:Terminal window cp .env.example .env -
Create the directories and the secrets, and mirror the password into
.env:Terminal window mkdir -p .secrets volumes/mysql volumes/storageopenssl rand -base64 32 | tr -d '\n' > .secrets/db_pwd.txtopenssl rand -base64 32 | tr -d '\n' > .secrets/db_root_pwd.txtsed -i "s|^DB_PWD_INLINE=.*|DB_PWD_INLINE=$(cat .secrets/db_pwd.txt)|" .env -
Hand the storage directory to the user Apache runs as, uid 33. Sessions are written there, and without write access no login can complete:
Terminal window sudo chown -R 33:33 volumes/storage -
Start it:
Terminal window docker compose up -ddocker compose logs easyappointments-app --followWait for
apache2 -D FOREGROUND. -
Open
https://<APP_TRAEFIK_HOST>/index.php/installationfrom the VPN — the route shipsaccess-vpnuntil the wizard has run, because the wizard creates the administrator account for whoever reaches it first. Afterwards log in at/index.php/user/login, then setAPP_TRAEFIK_ACCESS=access-publicin.envanddocker compose up -dif the booking page is to be public.
Verify
Section titled “Verify”docker compose ps # two services, healthyThen log in, create one service and one provider, and book an appointment from a private browser window. Logging in successfully is what proves step 3 worked.
Going further
Section titled “Going further”Choosing this over Cal.diY
Section titled “Choosing this over Cal.diY”Both book appointments. This one is PHP and MariaDB with a long track record and a small footprint; Cal.diY is a Next.js application with routing forms, team scheduling and workflows — and a heavier stack. If the need is one-to-one booking on a host with a modest memory budget, this is the simpler answer.
The compose file passes no mail settings. Booking notifications are configured in
the interface — Admin → Settings → Business → Email — and the SMTP host and
credentials live in the database, not in .env. Until they are set, nobody is
told about a booking.
Backup
Section titled “Backup”| Database | MariaDB, container easyappointments-db, database easyappointments, user easyappointments |
| Password | .secrets/db_pwd.txt |
| State | volumes/mysql (database) · volumes/storage (uploads, generated files) |
| Quiescing | Not needed — the dump is consistent on its own. |
For borgmatic:
mariadb_databases: - name: easyappointments container: easyappointments-db username: easyappointments password: "{credential file /srv/docker/apps/easyappointments/.secrets/db_pwd.txt}"Appointments are database rows, so an older database comes back without the bookings made since — and the people who made them still expect to be seen. Reconcile against the notification mail before resuming.
The database and volumes/storage come back from the same backup run, so
generated files match the rows that reference them.
Restore order: database, then the application.
Updates
Section titled “Updates”-
Read the release notes.
-
Back up the database and
volumes/storagetogether. -
Raise
APP_TAGin.env, then:Terminal window docker compose pull && docker compose up -d -
Log in and open the calendar. A schema change surfaces there.
Troubleshooting
Section titled “Troubleshooting”Login returns to the login page with no error. Sessions cannot be written.
volumes/storage is not owned by uid 33 — this is the failure step 3 prevents.
The install wizard appears again after setup. The database is empty or
unreachable. Check docker compose logs db.
Repository files
Section titled “Repository files”apps/easyappointments/README.md— setup, the comparison table, known issuesapps/easyappointments/UPSTREAM.md— source and upgrade checklist
Official sources
Section titled “Official sources”© 2026 SecDockBlueCode Apache-2.0Site content CC BY-NC 4.0