Configure the instance domain from .env instead of compose.yml

compose.yml was tracked but had to be edited per deployment, so every
update collided with the local change ("your local changes would be
overwritten by merge"). The domain now comes from STOAT_DOMAIN via
compose interpolation, and host.docker.internal is mapped unconditionally
so a host-side proxy needs no edit either. Nothing in compose.yml has to
be touched any more.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-09-09 00:26:08 +03:00
co-authored by Claude Opus 5
parent 71b9b7fe17
commit ea19a74c12
3 changed files with 34 additions and 32 deletions
+5
View File
@@ -4,6 +4,11 @@
# extra_hosts в compose.yml, поэтому TLS валидный и NAT loopback не нужен. # extra_hosts в compose.yml, поэтому TLS валидный и NAT loopback не нужен.
STOAT_API_URL=https://chat.example.com/api STOAT_API_URL=https://chat.example.com/api
# Домен вашего Stoat — тот же, что в STOAT_API_URL, без схемы.
# Используется в compose.yml: контейнер резолвит его в сам хост, где внешний
# Caddy держит валидный TLS. Сам compose.yml править не нужно.
STOAT_DOMAIN=chat.example.com
# Токен бота: Settings → My Bots → создать бота → скопировать токен. # Токен бота: Settings → My Bots → создать бота → скопировать токен.
STOAT_BOT_TOKEN= STOAT_BOT_TOKEN=
+7 -11
View File
@@ -71,7 +71,8 @@ openssl rand -hex 32 # → JWT_SECRET
Минимум, что нужно указать: Минимум, что нужно указать:
```dotenv ```dotenv
STOAT_API_URL=https://stoat.example.com/api STOAT_API_URL=https://chat.example.com/api
STOAT_DOMAIN=chat.example.com
STOAT_BOT_TOKEN=<токен бота> STOAT_BOT_TOKEN=<токен бота>
PUBLIC_URL=https://music.example.com PUBLIC_URL=https://music.example.com
JWT_SECRET=<случайные 32 байта> JWT_SECRET=<случайные 32 байта>
@@ -80,18 +81,13 @@ JWT_SECRET=<случайные 32 байта>
`STOAT_API_URL` указывается публичный (`https://домен/api`): бот ведёт себя как обычный клиент — `STOAT_API_URL` указывается публичный (`https://домен/api`): бот ведёт себя как обычный клиент —
ходит в API, gateway и LiveKit через тот же внешний прокси с валидным TLS, что и браузеры. ходит в API, gateway и LiveKit через тот же внешний прокси с валидным TLS, что и браузеры.
### 4. Указать домен инстанса в `compose.yml` ### 4. Про `STOAT_DOMAIN`
Бот запускается **отдельным compose-проектом** и с внутренним Caddy инстанса никак не связан. Бот запускается **отдельным compose-проектом** и с внутренним Caddy инстанса никак не связан.
В [compose.yml](compose.yml) поправьте одну строку — домен вашего Stoat: `STOAT_DOMAIN` из `.env` подставляется в `extra_hosts`, и контейнер резолвит домен инстанса
в сам хост, где внешний Caddy держит 443 с валидным сертификатом — так бот не зависит от
```yaml NAT loopback на роутере. **Сам [compose.yml](compose.yml) править не нужно**, иначе `git pull`
extra_hosts: будет конфликтовать с обновлениями.
- "chat.example.com:host-gateway"
```
Эта запись заставляет контейнер резолвить домен инстанса в сам хост, где внешний Caddy держит
443 с валидным сертификатом. Так бот не зависит от NAT loopback на роутере.
### 5. Повесить панель на внешний Caddy ### 5. Повесить панель на внешний Caddy
+22 -21
View File
@@ -1,21 +1,22 @@
name: stoat-mbot name: stoat-mbot
services: # Этот файл править не нужно: всё настраивается в .env, который docker compose
mbot: # читает и для подстановки переменных, и как env_file сервиса.
build: . services:
restart: always mbot:
env_file: .env build: .
ports: restart: always
# Наружу не торчит: домен вешается на внешний Caddy хоста. env_file: .env
- "127.0.0.1:3005:3005" ports:
extra_hosts: # Наружу не торчит: домен вешается на внешний Caddy хоста.
# Домен Stoat резолвится в хост, где внешний Caddy держит валидный TLS. - "127.0.0.1:3005:3005"
# Так бот ходит в API, gateway и LiveKit ровно как обычный клиент, extra_hosts:
# без зависимости от NAT loopback на роутере. # Домен Stoat (STOAT_DOMAIN в .env) резолвится в сам хост, где внешний
# Замените на свой домен: # Caddy держит валидный TLS. Так бот ходит в API, gateway и LiveKit ровно
- "chat.example.com:host-gateway" # как обычный клиент, без зависимости от NAT loopback на роутере.
# Раскомментируйте, если YTDLP_PROXY указывает на прокси, поднятый на хосте: - "${STOAT_DOMAIN:-stoat.invalid}:host-gateway"
# - "host.docker.internal:host-gateway" # Для YTDLP_PROXY, указывающего на прокси, поднятый на хосте.
volumes: - "host.docker.internal:host-gateway"
# cookies.txt для yt-dlp и/или локальная медиатека volumes:
- ./data:/data # cookies.txt для yt-dlp и/или локальная медиатека
- ./data:/data