Минимальный пример для одной жирной машины, где можно поднимать много независимых dev-сред.
Что внутри:
- один общий
caddyна хосте (caddy-docker-proxy) - много sandbox-окружений через
docker compose -p <env_id> - в каждом sandbox:
api(FastAPI)web(Next.js)postgres
- красивые URL вместо сырых портов
./scripts/create-env.sh env-101Одна команда — и всё готово. Скрипт сам:
- Поднимет Caddy (если ещё не запущен)
- Запустит sandbox-окружение
- Выведет URL-ы
Можно поднять сколько угодно сред:
./scripts/create-env.sh env-101
./scripts/create-env.sh env-102URL-ы:
http://env-101.dev.localtest.me-> webhttp://api.env-101.dev.localtest.me-> api
localtest.me резолвится в 127.0.0.1, так что для локальной отладки это удобно. Для внутренней сети замени BASE_DOMAIN на свой домен, например dev.internal.
./scripts/destroy-env.sh env-101caddy/ # общий reverse proxy на хосте
sandbox/ # шаблон одной среды
scripts/ # create/destroy helpers
Caddy живёт отдельно и постоянно. create-env.sh поднимает его автоматически при первом запуске. Новые sandbox-окружения не редактируют его конфиг руками. Вместо этого web и api получают Docker labels, например:
env-101.dev.localtest.meapi.env-101.dev.localtest.me
Caddy видит эти labels через caddy-docker-proxy и автоматически публикует маршруты.
Web-контейнер использует extra_hosts с host-gateway, чтобы домен api.*.dev.localtest.me резолвился в хост-машину (а не в 127.0.0.1 внутри контейнера). Это позволяет getServerSideProps ходить в API через Caddy.
Один и тот же sandbox/docker-compose.yml можно поднимать много раз:
docker compose -p env-101 -f sandbox/docker-compose.yml up -d
docker compose -p env-102 -f sandbox/docker-compose.yml up -dCompose сам изолирует контейнеры, сети и тома по имени проекта.
ENV_ID— идентификатор среды, напримерenv-101BASE_DOMAIN— базовый домен, по умолчаниюdev.localtest.mePOSTGRES_PASSWORD— пароль Postgres, по умолчаниюpostgres
Это dev-демо. Здесь нет:
- миграций
- secrets manager
- ClickHouse / Redis
- auth
- TTL / garbage collection