MAATRIX / Блог / EasyAppointments в Docker Compose: готовый файл

EasyAppointments в Docker Compose: готовый файл

MAATRIX

Если вы уже пробовали ставить EasyAppointments вручную — PHP, Composer, MariaDB, права на директории — знаете, что половина времени уходит не на саму систему записи, а на то, чтобы окружение вокруг неё завелось одинаково на всех серверах. Docker Compose снимает эту проблему: один файл описывает контейнер приложения и контейнер базы, docker compose up -d — и через минуту у вас рабочий сервис записи клиентов, который можно поднять заново на любом VPS без разбора граблей вручную.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое EasyAppointments и когда она нужна

EasyAppointments — open-source система онлайн-бронирования: клиент сам выбирает специалиста, услугу и свободный слот на публичной странице, а вы получаете единый календарь без двойных записей и без звонков «а можно на четверг после обеда». Внутри — карточки специалистов и услуг, рабочие часы и перерывы, email-уведомления клиенту и исполнителю, встраиваемый виджет для сайта (iframe или прямая ссылка), базовая синхронизация с Google Calendar.

Кому подходит: салонам красоты, стоматологиям и медицинским кабинетам, репетиторам, консультантам, автосервисам, юристам — везде, где есть простая связка «специалист + услуга + время». Это не CRM: нет встроенных платежей, сложной аналитики и ролей с гибкими правами. Зато это ровно тот случай, когда не нужно переплачивать за функциональность, которой вы не будете пользоваться, — система лёгкая и по ресурсам, и по порогу входа.

Технически это PHP-приложение (CodeIgniter) с базой MySQL/MariaDB. Официальный образ alextselegidis/easyappointments уже включает веб-сервер и PHP внутри контейнера — снаружи вам нужна только база данных и реверс-прокси для домена и HTTPS.

Что понадобится перед стартом

Минимальный набор:

  • VPS с Docker и Docker Compose plugin (2 ГБ RAM хватает с запасом даже с MySQL в соседнем контейнере);
  • домен или поддомен, направленный A-записью на IP сервера — например, booking.yourdomain.com;
  • открытые порты 80 и 443 (для HTTP и HTTPS через реверс-прокси).

Если Docker ещё не установлен, порядок настройки production-окружения с Compose разобран в отдельной статье про подготовку сервера под Compose-стеки. Если вы уже ставили EasyAppointments классическим способом и хотите сравнить подходы, есть параллельная статья — EasyAppointments на Ubuntu 24.04: пошаговая установка.

Создаём рабочую директорию проекта:

mkdir -p ~/easyappointments && cd ~/easyappointments

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Готовый docker-compose.yml

Ниже — рабочая конфигурация из двух сервисов: приложение и MySQL. Данные базы и файлы приложения вынесены в именованные тома, чтобы обновления и перезапуски контейнеров не теряли ни записи, ни загруженные аватары специалистов.

version: "3.9"

services:
  easyappointments:
    image: alextselegidis/easyappointments:latest
    container_name: ea-app
    restart: unless-stopped
    depends_on:
      - mysql
    environment:
      BASE_URL: "https://booking.yourdomain.com"
      DEBUG_MODE: "false"
      DB_HOST: "mysql"
      DB_PORT: "3306"
      DB_NAME: "easyappointments"
      DB_USERNAME: "ea_user"
      DB_PASSWORD: "СложныйПароль_замените!"
      DB_ROOT_PASSWORD: "ЕщёОдинСложныйПароль_замените!"
      LANGUAGE: "ru"
      DATE_FORMAT: "DD-MM-YYYY"
      TIME_FORMAT: "army"
    volumes:
      - ea_storage:/var/www/html/storage
    networks:
      - ea_net
    # порт наружу открывать не обязательно, если перед контейнером стоит
    # reverse proxy на docker-сети (см. раздел про Traefik ниже);
    # для быстрой проверки без домена раскомментируйте:
    # ports:
    #   - "8080:80"

  mysql:
    image: mysql:8.0
    container_name: ea-mysql
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: "easyappointments"
      MYSQL_USER: "ea_user"
      MYSQL_PASSWORD: "СложныйПароль_замените!"
      MYSQL_ROOT_PASSWORD: "ЕщёОдинСложныйПароль_замените!"
    volumes:
      - ea_mysql_data:/var/lib/mysql
    networks:
      - ea_net
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  ea_storage:
  ea_mysql_data:

networks:
  ea_net:

Три вещи, которые нужно заменить своими значениями до запуска:

  • BASE_URL — конечный адрес, по которому будет открываться сервис (с https://, даже если сертификата пока нет — привяжете следом);
  • DB_PASSWORD и DB_ROOT_PASSWORD — сгенерируйте случайные строки, не оставляйте пример из статьи;
  • имя контейнера БД в DB_HOST должно совпадать с именем сервиса mysql — Docker Compose резолвит его как DNS-имя внутри сети ea_net, отдельно прописывать IP не нужно.

Обратите внимание: переменные окружения официального образа могут немного отличаться между версиями — если после обновления образа приложение не стартует с прежним .yml, проверьте актуальный список переменных в .env-example внутри репозитория проекта на GitHub (alextselegidis/easyappointments, каталог docker/) — это надёжнее, чем ориентироваться на статью многолетней давности.

Запуск и настройка через веб-мастер

Поднимаем стек:

docker compose up -d
docker compose logs -f easyappointments

Первый старт контейнера с MySQL занимает 20-40 секунд — база инициализируется, и приложение может несколько раз перезапуститься с ошибкой подключения, пока MySQL не поднимется полностью. Это ожидаемо, restart: unless-stopped разрулит гонку сам; если хотите её убрать, добавьте в easyappointments секцию depends_on с условием condition: service_healthy, опираясь на healthcheck из блока mysql выше.

Проверяем, что оба контейнера в статусе Up:

docker compose ps

Дальше — если временно тестируете без домена и реверс-прокси, откройте порт 8080 (раскомментировав строку ports в docker-compose.yml) и зайдите на http://ВАШ_IP:8080. Мастер первичной настройки попросит:

  1. подтвердить параметры подключения к базе (они уже переданы через переменные окружения, обычно достаточно нажать «далее»);
  2. создать первого администратора — логин, пароль, email;
  3. задать название компании и часовой пояс.

После завершения мастера вы попадаете в админ-панель, где создаются специалисты (Users → Providers), услуги (Services) и рабочие часы. Публичная страница записи для клиентов доступна по корневому адресу — её же можно встроить на существующий сайт через <iframe>.

Домен и HTTPS через Traefik

Открывать приложение по IP и порту 8080 нормально для теста, но для продакшена нужен нормальный домен с шифрованием — иначе форма записи, где клиент вводит имя, телефон и email, будет уходить по незащищённому каналу. Проще всего добавить реверс-прокси Traefik в ту же docker-сеть — он сам выпустит сертификат Let's Encrypt и продлит его без вашего участия.

Общий подход к Traefik как reverse proxy для Docker подробно разобран в статье Traefik как reverse proxy для Docker — здесь только то, что специфично для EasyAppointments. В docker-compose.yml добавьте лейблы к сервису easyappointments вместо секции ports:

  easyappointments:
    # ...остальные параметры без изменений
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.ea.rule=Host(`booking.yourdomain.com`)"
      - "traefik.http.routers.ea.entrypoints=websecure"
      - "traefik.http.routers.ea.tls.certresolver=letsencrypt"
      - "traefik.http.services.ea.loadbalancer.server.port=80"
    networks:
      - ea_net
      - traefik_net

Сеть traefik_net должна быть внешней (external: true) и совпадать с той, в которой у вас уже поднят сам Traefik. После docker compose up -d сертификат выпустится автоматически при первом обращении к домену — обычно за 10-30 секунд, при условии что DNS уже указывает на сервер.

Если вместо Traefik вы используете Caddy — принцип тот же (один блок на домен, автовыпуск SSL); в конфиг Caddy достаточно проксировать домен на ea-app:80 внутри общей docker-сети.

Email-уведомления и резервное копирование

EasyAppointments отправляет клиентам и специалистам письма о новой записи, отмене и напоминания — без рабочей почты эта функция просто не выполняет свою задачу, а письма либо не уходят вовсе, либо массово падают в спам. SMTP настраивается не в docker-compose.yml, а внутри самого приложения — зайдите в Settings → General и укажите:

SMTP Host: smtp.yourmailprovider.com
SMTP Port: 587
SMTP Username: notifications@yourdomain.com
SMTP Password: (пароль приложения, не обычный пароль от почты)
SMTP Security: tls

Если планируете поднимать собственный почтовый сервер на этом же VPS, для стабильной доставки критична PTR-запись и настроенные SPF/DKIM — без них письма с нового IP уходят в спам у Gmail и Mail.ru почти гарантированно. Разворачивание своего сервера описано в статье Postfix на Ubuntu 24.04: пошаговая установка, но для старта проще подключить внешний SMTP-сервис с уже прогретой репутацией отправителя — это быстрее и надёжнее.

Резервное копирование в Docker-варианте — по сути дамп базы и снапшот тома с файлами:

# дамп базы данных
docker compose exec mysql sh -c \
  'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" easyappointments' > ea_backup_$(date +%F).sql

# архив тома с загруженными файлами (аватары, вложения)
docker run --rm -v easyappointments_ea_storage:/data -v $(pwd):/backup \
  alpine tar czf /backup/ea_storage_$(date +%F).tar.gz -C /data .

Поставьте это в cron раз в сутки с ротацией старых архивов. Для более серьёзного подхода с версионированием и хранением вне сервера подойдёт связка через отдельный контейнер — она разобрана в статье Duplicati в Docker Compose: готовый файл.

Обновление до новой версии — стандартная процедура для Compose-стека:

docker compose pull
docker compose up -d

Перед обновлением на проде обязательно сделайте свежий дамп базы — миграции схемы между мажорными версиями EasyAppointments иногда меняют структуру таблиц, и откатиться без бэкапа будет нечем.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли использовать MariaDB вместо MySQL в этом compose-файле?

Да, замените образ mysql:8.0 на mariadb:11 — переменные окружения для создания базы и пользователя у обоих образов совпадают дословно, менять DB_* переменные в сервисе easyappointments не нужно.

Как перенести существующую установку EasyAppointments в Docker?

Сделайте дамп текущей базы (mysqldump), поднимите этот стек, дождитесь первого старта (таблицы создадутся мастером или миграциями), затем импортируйте дамп в контейнер MySQL и скопируйте содержимое директории с загруженными файлами в том ea_storage.

Приложение стартует, но выдаёт ошибку подключения к базе.

Почти всегда это гонка при первом запуске — MySQL ещё не успел инициализироваться. Подождите 30-40 секунд и перезапустите контейнер приложения: docker compose restart easyappointments. Если ошибка не уходит, проверьте, что DB_HOST в точности совпадает с именем сервиса mysql из docker-compose.yml.

Нужен ли отдельный SSL-сертификат внутри контейнера EasyAppointments?

Нет, HTTPS терминируется на уровне реверс-прокси (Traefik или Caddy) — сам контейнер приложения слушает обычный HTTP-порт 80 внутри docker-сети.

Сколько ресурсов сервера реально нужно?

Для одной небольшой команды специалистов достаточно 1-2 vCPU и 2 ГБ RAM с запасом — MySQL под такую нагрузку почти не расходует ресурсов. При росте базы клиентов и записей стоит ориентироваться на объём диска под том ea_mysql_data, а не на CPU.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →