Appearance
Второй стенд на одном сервере
Сценарий: на сервере уже работает продовый стенд, и рядом нужен независимый второй — демо, стенд заказчика, тестовый контур. Референс — реально работающие стенды из этого репозитория: orbita.bamboo2panda.ru (SaaS prod, он же держит Traefik), app.orbitaitsm.ru (on-premise демо; на корне orbitaitsm.ru — лендинг) и TurboBPM (другой бренд, см. стенд под своим брендом).
Принцип разделения
Общий компонент между стендами — только Traefik первого стенда. Всё остальное у каждого стенда своё:
- свой checkout репозитория (
/opt/hosting/<стенд>/prod); - свой compose-файл и env-файл (
docker-compose-orbitaitsm.yml+orbitaitsm.env— готовый образец); - свой compose-проект (
-p), свои контейнеры с уникальными именами (orbitaitsm_prod_*); - своя внутренняя Docker-сеть для БД/Redis/поиска/воркеров;
- свои volumes (БД, Meilisearch, SeaweedFS).
К общей сети Traefik подключаются только сервисы, которые он маршрутизирует: frontend, backend, reverb, seaweedfs, docs, landing. Traefik различает стенды по Host()-правилам в labels.
Внутренние сервисы — только в свою сеть
Не подключайте database/redis/meilisearch/queue/scheduler второго стенда к общей сети Traefik. У первого стенда там уже есть контейнер с hostname database — если оба окажутся в одной сети, Docker DNS будет отдавать это имя случайным образом то на один, то на другой контейнер. Это пережитый инцидент: у демо-стенда «прыгал» коннект к БД с ошибкой password authentication failed for user orbita.
Порядок развёртывания
1. DNS
A-запись домена второго стенда → публичный IP того же сервера. Если ACME-резолвер первого стенда работает через Cloudflare DNS-01 — домен должен обслуживаться в том же Cloudflare-аккаунте.
2. Checkout и конфигурация
bash
git clone <repo_url> /opt/hosting/orbitaitsm/prod
cd /opt/hosting/orbitaitsm/prod
# Свой env: скопировать шаблон, заполнить домен и НОВЫЕ секреты
# (не переиспользуйте APP_KEY/пароли первого стенда)
cp onpremise.env.example orbitaitsm.envВ compose-файле второго стенда проверьте имя внешней сети Traefik — оно должно совпадать с реально существующей сетью первого стенда:
bash
docker network ls | grep orbita-network
# при необходимости поправить networks.orbita-network.name в compose-файле3. Запуск
Обязательно со своим именем проекта -p — оно изолирует volumes и дефолтные имена:
bash
docker compose --env-file orbitaitsm.env -p orbitaitsm_prod \
-f docker-compose-orbitaitsm.yml build
docker compose --env-file orbitaitsm.env -p orbitaitsm_prod \
-f docker-compose-orbitaitsm.yml up -d
docker exec orbitaitsm_prod_backend php artisan migrate --forceДальше инициализация как в обычном on-premise.
4. Проверка сертификата
bash
docker logs orbita_prod_traefik 2>&1 | grep -i <домен-второго-стенда>
curl -I https://<домен-второго-стенда> # → 200И убедитесь, что первый стенд продолжает работать — главный риск этого сценария именно в задетой сети/Traefik.
Перенос демо-данных тенанта (опционально)
Если второй стенд — демо с данными из прода, тенант переносится так (полный рецепт с командами — internal-docs/orbitaitsm-demo-setup.md):
- На проде:
php artisan tenant:backup --tenant=<ID>→ SQL-файл сINSERT ... ON CONFLICT DO NOTHING, достать черезdocker cp. - На новом стенде после
migrate --force, но до любых других данных: вручную вставить строку тенанта с тем же id вtenants(и поправить sequence), затем импортировать SQL-дамп. - Скопировать вложения тенанта из SeaweedFS-тома старого стенда в новый (ключи не меняются, т.к. tenant_id совпал).
- Переиндексировать поиск:
php artisan scout:import(илиsearch:rebuild). - Отключить публичную регистрацию и OAuth (
sys_settings:registration_enabled,oauth_*_enabled→false). - Сменить пароли перенесённых админ-аккаунтов до того, как отдать демо наружу — хэши приехали с прода как есть.
Обновление второго стенда
Каждый стенд обновляется независимо из своего checkout, теми же командами, что и основной, но со своими -p, --env-file и -f. Если настроен GitHub Actions деплой — для второго стенда используется отдельный workflow (deploy-orbitaitsm.yml, запуск вручную через workflow_dispatch).