---
title: "Deploy Easy!Appointments | (Just Updated) Online Appointment Scheduling With REST API, Admin Password Generated"
description: "Easy!Appointments online appointment scheduling and booking, REST API"
category: "Other"
url: https://railway.com/deploy/easyappointments-or-just-updated-online-
---

# Deploy Easy!Appointments | (Just Updated) Online Appointment Scheduling With REST API, Admin Password Generated

Easy!Appointments online appointment scheduling and booking, REST API

**[Deploy Easy!Appointments | (Just Updated) Online Appointment Scheduling With REST API, Admin Password Generated on Railway](https://railway.com/template/easyappointments-or-just-updated-online-)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/easyappointments-or-just-updated-online-/manifest.json

- **Creator:** SuperSlowSloth
- **Category:** Other

## Template content

### mariadb

- **Image:** mariadb:11.8@sha256:6422478cb8e159f080fb1d8ccf65101e26fe51385787fde7d16c3b165a331f15
- **Start command:** `/bin/sh -c 'set -e; M=$(cat /sys/fs/cgroup/memory.max 2>/dev/null || echo max); if [ "$M" != max ]; then B=$((M / 2 / 1048576)); [ "$B" -lt 128 ] && B=128; else B=512; fi; export MARIADB_DATABASE=easyappointments MARIADB_USER=easyappointments; echo "[railway] uid=$(id -u) innodbBufferPoolMB=$B owner=$(stat -c %u:%g /var/lib/mysql)"; exec docker-entrypoint.sh mariadbd --datadir=/var/lib/mysql/data --innodb-buffer-pool-size=${B}M --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci'`

### easyappointments

- **Image:** ghcr.io/bon5co/easyappointments-railway:1.6.1@sha256:14408d86ccf9333368dfc2b3788e52cc46c865c1dd9e31b1675239958e703e28
- **Health check:** /
- **Public domain:** Yes

## Documentation

# Deploy and Host Easy!Appointments on Railway

**Built for an LLM agent to deploy and use.** The deploy form has no fields to fill: the administrator password is generated, the database is wired in, the Easy!Appointments installer runs by itself on first boot, and uploads, backups and the database sit on volumes. Easy!Appointments is an open-source, self-hosted appointment scheduler: a public booking page for customers, calendars for providers and secretaries, services, working plans, email notifications, Google Calendar sync and a REST API.

## About Hosting Easy!Appointments

This template runs two services: **easyappointments** (the application on one public domain, with a volume at `/var/www/html/storage` holding uploads, backups, logs and sessions) and **mariadb** (MariaDB 11.8 with a volume at `/var/lib/mysql`). Appointments, customers, services and settings survive redeploys.

**No wizard, no default login.** Upstream expects someone to open a browser and fill in an installation form. This template runs the same installer at first boot with the administrator `admin` and the generated `EA_ADMIN_PASSWORD` (32 characters), so the instance is never reachable half-installed. The wrapper refuses to start with a password under 12 characters. The healthcheck is the front page `/`, which answers `307` and then `503` until the installer has finished, so Railway marks the deploy live only once the administrator exists.

**What the wrapper fixes for Railway.** Apache is moved onto Railway's injected `PORT` (upstream listens on 80). The base URL is derived from the public domain, so booking links and emails use `https`. Sessions are no longer bound to the client IP (`sess_match_ip` off), because Railway's edge address changes per request and would sign every user out on the next click. The storage directory is reseeded and handed to the web user on every start, because a volume arrives root-owned and hides the `.htaccess` files that keep uploads and backups private. A half-finished install is cleared before a new one starts. Upstream is Easy!Appointments 1.6.1, pinned by digest.

**Using it.** Sign in at `https://YOUR_DOMAIN/index.php/login` as `admin` with `EA_ADMIN_PASSWORD` (the username is fixed, it is not a template variable). Customers book at `https://YOUR_DOMAIN/`. To send email notifications set the SMTP variables on the `easyappointments` service (`MAIL_PROTOCOL=smtp`, `MAIL_SMTP_HOST`, `MAIL_SMTP_PORT`, `MAIL_SMTP_USER`, `MAIL_SMTP_PASS`, `MAIL_SMTP_CRYPTO`); the application works without them.

### Agent contract

- Public URL: `https://RAILWAY_PUBLIC_DOMAIN` (the generated domain of the `easyappointments` service; the REST API is under `/index.php/api/v1`)
- Private URL: `http://easyappointments.railway.internal:8080`
- Credentials: the variable `EA_ADMIN_PASSWORD` on the `easyappointments` service, for the fixed username `admin` (the username is not a template variable)
- Auth: HTTP Basic on the REST API, `Authorization: Basic base64(admin:EA_ADMIN_PASSWORD)` (`curl -u`). A request with no credentials, or with a wrong password, answers `401`, for reads and for writes alike.
- Health: `GET /` returns 200 (it answers 307 and then 503 for the few seconds the installer runs on the first boot)

```bash
#!/bin/sh
# needs: RAILWAY_PUBLIC_DOMAIN, EA_ADMIN_PASSWORD (variables of the easyappointments service); also curl. Creates one throwaway customer.
R="https://$RAILWAY_PUBLIC_DOMAIN"; B="$R/index.php"
# first boot runs the installer (under a minute); wait for the front page
n=0; until [ "$(curl -s -o /dev/null -w '%{http_code}' "$R/")" = 200 ]; do n=$((n+1)); [ "$n" -le 60 ] || break; sleep 5; done
curl -s -o /dev/null -w "health: %{http_code}\n" "$R/"
curl -s -o /dev/null -w "read with key: %{http_code}\n" -u "admin:$EA_ADMIN_PASSWORD" "$B/api/v1/customers"
curl -s -o /dev/null -w "read without key: %{http_code}\n" "$B/api/v1/customers"
E="agent$(date +%s)@example.com"
D="{\"firstName\":\"Agent\",\"lastName\":\"Test\",\"email\":\"$E\",\"phone\":\"+10000000001\"}"
curl -s -o /dev/null -w "write with key: %{http_code}\n" -u "admin:$EA_ADMIN_PASSWORD" -X POST "$B/api/v1/customers" -H "Content-Type: application/json" -d "$D"
curl -s -u "admin:$EA_ADMIN_PASSWORD" "$B/api/v1/customers" | grep -c "$E" | sed 's/^/customer found after write: /'
curl -s -o /dev/null -w "write without key: %{http_code}\n" -X POST "$B/api/v1/customers" -H "Content-Type: application/json" -d "$D"
curl -s -o /dev/null -w "write with wrong key: %{http_code}\n" -u "admin:${EA_ADMIN_PASSWORD}x" -X POST "$B/api/v1/customers" -H "Content-Type: application/json" -d "$D"
```

A fresh deploy prints `health: 200`, `read with key: 200`, `read without key: 401`, `write with key: 201`, `customer found after write: 1`, `write without key: 401` and `write with wrong key: 401`.

## Why Deploy Easy!Appointments on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Easy!Appointments on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

- **Agent-ready** - no deployer fields, a contract block and one script that proves the installer finished, an authenticated read and write over the REST API, and the refusal of a write with no key or a wrong one.
- **No wizard and no default login** - the administrator is created at first boot from a generated password.
- **Data survives redeploys** - the database and the storage directory sit on volumes.
- **Pinned** - the upstream image is pinned by digest and the wrapper by tag and digest.
- **Your bookings on your domain** - customers, appointments and calendars stay on infrastructure you control.

## Common Use Cases

- **Run a booking page for a small business** - salons, clinics, tutors, consultants and repair shops let customers pick a service, a provider and a slot.
- **Replace a paid scheduling SaaS** - keep customer data and calendars on your own domain without per-seat pricing.
- **Several providers and services** - each provider has a working plan and breaks, each service has its own duration and price.
- **Agent-driven scheduling** - give an agent the REST API to create customers, read availabilities and book or cancel appointments.

## Dependencies for Easy!Appointments Hosting

- The easyappointments service and the mariadb service with their volumes, created by the template. A custom domain and an SMTP account are optional.

### Deployment Dependencies

- [Easy!Appointments repository](https://github.com/alextselegidis/easyappointments)
- [Easy!Appointments documentation](https://easyappointments.org/docs.html)
- [Wrapper image source](https://github.com/bon5co/easyappointments-railway)


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/easyappointments-or-just-updated-online-
