Deploy Easy!Appointments

Appointment scheduler with a public booking page for your business

Deploy Easy!Appointments

Just deployed

/var/lib/mysql

Just deployed

Just deployed

/var/www/html/storage

Just deployed

/data

Just deployed

/data

Deploy and Host Easy!Appointments on Railway

Easy!Appointments is an open-source appointment scheduler for businesses that book people into time slots: clinics, salons, tutors, garages and council offices. Customers open a public booking page, pick a service, a provider and a free slot, and get a confirmation email; staff work from an admin back office with a calendar, customer records, per-provider working plans and booking rules. Maintained since 2013 under GPL-3.0, it ships 30-plus languages and syncs two ways with Google Calendar and CalDAV.

Self-host Easy!Appointments on Railway and this template wires up the production shape rather than a single container. easyappointments serves the booking page and the back office through Apache and mod_php. MySQL holds every appointment, customer and setting. Redis stores sessions, so the web tier keeps no state and a redeploy signs nobody out. easyappointments-cron runs the commands upstream documents as cron jobs: calendar sync, retention cleanup and a daily backup onto its own volume. mailpit provides an SMTP host with a password-protected inbox. The first administrator is created from your own variables while the container boots, before the public port opens, so no setup wizard is left open for a stranger to finish.

Diagram of the Easy!Appointments services, MySQL, Redis and Mailpit on Railway

Getting Started with Easy!Appointments on Railway

Set EA_ADMIN_PASSWORD before deploying — the only value you must supply, read once while the database is still empty. EA_ADMIN_USERNAME (default administrator), EA_ADMIN_EMAIL and EA_COMPANY_NAME are worth setting too; the last is the business name on the booking page.

When the deploy finishes, open the easyappointments service's public URL. You land on the booking page, already populated with one starter service and provider, so the flow works immediately. Sign in at /index.php/login and the back office opens on the calendar.

Then do four things. Under Settings → Business Logic, set your working days and hours; that becomes the default plan for every provider added later. Under Services, rename the starter service and add the rest with durations and prices. Under Users → Providers, replace the seeded Jane Doe with real staff and tick the services each offers; that account has a random password, so set one. Finally book a test appointment from Go To Booking Page: it should reach the calendar within seconds, and three emails — customer, provider, administrator — should be waiting in the mailpit inbox, which captures mail rather than delivering it.

Public booking page offering appointment times for a dental consultation

Weekly admin calendar showing a booked consultation appointment

Editing the Teeth Whitening service duration and price

Appointment details panel with the customer's contact information

About Hosting Easy!Appointments

Booking data is sensitive: names, phone numbers, and a record of when someone visited a clinic. Self-hosting keeps it in a database you control, under your own retention policy, with no per-seat price.

  • An embeddable booking page with per-service durations, slot intervals, booking limits and prices
  • Administrator, provider and secretary roles, each with a working plan and exceptions
  • Two-way Google Calendar and CalDAV sync, plus Jitsi and Google Meet links
  • Email notifications on booking, rescheduling and cancellation, with signed cancel and confirm links
  • A REST API, webhooks, LDAP login, an ALTCHA captcha and a data-retention period

The Railway split follows what upstream recommends for production: the web service is stateless and scalable once your hours are set, MySQL is the only durable store the app writes to, and Redis holds the sessions a file store would lose on each deploy.

Why Deploy Easy!Appointments on Railway

Railway removes the parts of PHP hosting that cost an afternoon:

  • MySQL and Redis provisioned, privately networked and managed
  • HTTPS, the domain and the certificate handled automatically
  • The first administrator created at boot from your variables
  • Scheduled maintenance as a real service with its own health check
  • Vertical scaling and logs one click away

Common Use Cases for Self-Hosted Easy!Appointments

  • A clinic or physiotherapy practice taking its own bookings rather than paying per practitioner for a seat
  • A driving school or tutoring service where each instructor has different hours and a different service list
  • A council office issuing timed slots to the public, keeping the record in-house

Dependencies for Easy!Appointments

  • easyappointments and easyappointments-cron — built from gridalpha/easyappointments-railway, a thin layer over upstream's published image alextselegidis/easyappointments
  • MySQL (mysql:9.4) — appointments, customers, services, providers and settings
  • Redis (redis:8.2) — the session store that makes the web tier stateless
  • mailpit (axllent/mailpit:latest) — SMTP host and inbox, so notification mail works immediately

Environment Variables Reference

VariablePurpose
EA_ADMIN_PASSWORDFirst administrator's password. Required; read only while the database is empty
EA_ADMIN_USERNAMELogin name for that account, default administrator
EA_ADMIN_EMAILWhere password resets and admin notifications go
EA_COMPANY_NAMEBusiness name shown on the public booking page
EA_TIMEZONEDefault timezone, e.g. Europe/London
LANGUAGEInterface language, e.g. english
MAIL_SMTP_HOSTSMTP host, pointing at Mailpit by default
GOOGLE_CLIENT_IDGoogle OAuth client for calendar sync

Deployment Dependencies

  • Source:
  • Docs:
  • Runtime: PHP 8.2 on Apache, with mysqli, gd, intl, ldap, redis

Hardware Requirements for Self-Hosting Easy!Appointments

ResourceMinimumRecommended
CPU1 vCPU2 vCPU
RAM512 MB1–2 GB
Storage1 GB5 GB with backups
RuntimePHP 8.2, MySQL 5.7+PHP 8.2, MySQL 8 or 9, Redis

A classic LAMP application, comfortable on very small instances; storage grows with the backups, not the bookings.

Self-Hosting Easy!Appointments with Docker

Upstream publishes a production image configured through environment variables. This runs it against a MySQL container:

docker network create ea

docker run -d --name ea-db --network ea \
  -e MYSQL_ROOT_PASSWORD=change-me -e MYSQL_DATABASE=ea mysql:9.4

docker run -d --name ea-app --network ea -p 8080:80 \
  -e BASE_URL=http://localhost:8080 -e DB_HOST=ea-db -e DB_NAME=ea \
  -e DB_USERNAME=root -e DB_PASSWORD=change-me \
  alextselegidis/easyappointments:latest

Open http://localhost:8080 and a setup wizard asks for an administrator account. The three jobs upstream recommends putting on cron are:

docker exec ea-app php index.php console sync
docker exec ea-app php index.php console cleanup
docker exec ea-app php index.php console backup

sync pushes and pulls provider calendars, cleanup deletes expired sessions and customer data past your retention window, and backup writes a gzipped dump into storage/backups. The maintenance service runs all three here.

How Much Does Easy!Appointments Cost to Self-Host?

Easy!Appointments is free and open source under GPL-3.0, with no paid tier, seat limit or feature gating — what you deploy is the whole product, and there is no licence key. The only cost is infrastructure: two small application services plus managed MySQL, Redis and Mailpit, together in the low single digits of dollars a month for a small practice.

FAQ

What is Easy!Appointments?

An open-source, self-hosted appointment scheduler written in PHP. It gives a business a public booking page plus an admin back office for services, providers, customers and a calendar. GPL-3.0, maintained since 2013.

Why does the template include Redis and a separate maintenance service?

Sessions are stored in files inside the container by default, so they vanish on every deploy; Redis moves them out, which keeps people signed in and lets the web tier be scaled. The maintenance service exists because calendar sync, retention cleanup and backups are scheduled command-line jobs, which a template cannot express as a cron entry.

How do I set up Google Calendar sync in self-hosted Easy!Appointments?

Create an OAuth client in Google Cloud with the Calendar API enabled, add your deployment's URL as an authorised redirect target, then set GOOGLE_SYNC_FEATURE, GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET — or enter them under Settings → Integrations. Providers then switch sync on per calendar.

How do I send real email instead of capturing it?

Replace MAIL_SMTP_HOST, MAIL_SMTP_PORT, MAIL_SMTP_USER, MAIL_SMTP_PASS and MAIL_SMTP_AUTH on both application services with your provider's values, set MAIL_SMTP_CRYPTO to tls, and point MAIL_FROM_ADDRESS at an address it may send from.


Template Content

More templates in this category

View Template
Rocky Linux
Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
47
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
51