Clients relied on /openrouter/ having no token check; v0.2.0 applies the guard to every prefix, so the missing header now shows up everywhere. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2 files changed
+89
No files matched your search
@@ -184,6 +184,41 @@ For OpenAI-compatible SDKs set `baseURL` to `https://proxy.bildme.ru/deepseek` a
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### `403 {"error":"invalid_token"}` on every path
|
||||||
|
|
||||||
|
The proxy answered, not the upstream — `X-Proxy-Token` is missing or wrong. The body is the proxy's own format; a real upstream error looks different (DeepSeek: `{"error":{"message":...,"type":...}}`).
|
||||||
|
|
||||||
|
The guard applies to **every** prefix. Before v0.2.0 `/openrouter/` was the one route without a token check — that exception is gone, so clients that relied on it must send the header too.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "X-Proxy-Token: $PROXY_SECRET" \
|
||||||
|
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
||||||
|
https://proxy.bildme.ru/deepseek/user/balance
|
||||||
|
```
|
||||||
|
|
||||||
|
For OpenAI-compatible SDKs put it in the default headers, next to `baseURL`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
option.WithBaseURL("https://proxy.bildme.ru/deepseek"),
|
||||||
|
option.WithHeader("X-Proxy-Token", os.Getenv("PROXY_SECRET")),
|
||||||
|
```
|
||||||
|
|
||||||
|
### `403 {"error":"ip_not_allowed"}`
|
||||||
|
|
||||||
|
The caller's source IP is not in `ALLOWED_CIDR`. Check the effective list:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec api-proxy cat /etc/caddy/matchers.caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upstream errors pass through unchanged
|
||||||
|
|
||||||
|
`401`, `404` or `5xx` with an upstream-shaped JSON body means the proxy did its job and the upstream rejected the request — check the API key, not the proxy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Monitoring
|
## Monitoring
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Переход nginx → Caddy + Let's Encrypt (proxy.bildme.ru)
|
||||||
|
|
||||||
|
Дата: 2026-09-20 · Профиль: refactoring · Репозиторий: `pub/elevenlabs.io`
|
||||||
|
|
||||||
|
## Задача
|
||||||
|
Заменить nginx на Caddy, оставить порт 8082 как есть, параллельно открыть 443 с сертификатом Let's Encrypt на `proxy.bildme.ru`. Предыстория — таймаут `api.deepseek.com` у клиента, из-за чего в прокси был добавлен маршрут `/deepseek/`.
|
||||||
|
|
||||||
|
## Аудит прода (62.84.98.250)
|
||||||
|
- 80/443 занимал хостовый nginx 1.18 (systemd): заглушка `/var/www/html` + vhost `tg.bildme.ru`, чей DNS уже указывал на `45.151.70.121`, сертификат истёк 14.07.2026 → потерь нет.
|
||||||
|
- Контейнер `api-proxy` из `/srv/elevenlabs` (не git), проброс `8082:8080`, образ из `git.realmanual.ru`.
|
||||||
|
- `docker-compose` 1.29.2 + Docker 28.2.2 → известная несовместимость (`KeyError: 'ContainerConfig'`).
|
||||||
|
|
||||||
|
## Изменения в репозитории
|
||||||
|
| Файл | Что |
|
||||||
|
|------|-----|
|
||||||
|
| `Caddyfile` | новый конфиг: сниппеты `(scrub)`, `(api)`, `(routes)`; маршруты в `route {}` — guard'ы отрабатывают до `handle_path` |
|
||||||
|
| `docker-entrypoint.sh` | генерация `matchers.caddy` / `guard.caddy` из `ALLOWED_CIDR` и `PROXY_SECRET`; обязательные `DOMAIN`, `ACME_EMAIL`; `caddy validate` перед стартом |
|
||||||
|
| `Dockerfile` | `caddy:2.11.4-alpine`, EXPOSE 80/443/8080 |
|
||||||
|
| `docker-compose.yml` | порты `80`, `443` (tcp+udp), `8082:8080`; тома `caddy_data`, `caddy_config` |
|
||||||
|
| `scripts/migrate-host-nginx.sh` | бэкап `/etc/nginx` + `/etc/letsencrypt`, отключение nginx и `certbot.timer`, проверка портов |
|
||||||
|
| `scripts/deploy.sh` | реальный прод-путь `/srv/elevenlabs`, приоритет `docker compose` v2 |
|
||||||
|
| `nginx/`, `ssl/` | удалены |
|
||||||
|
| `VERSION` | 0.2.0 |
|
||||||
|
|
||||||
|
Коммиты: `d71001a`, `e90d673`.
|
||||||
|
|
||||||
|
## Выполнено на сервере
|
||||||
|
1. Бэкап хостового nginx → `/root/nginx-backup-20260920-093758` (`nginx-T.dump`, `etc-nginx.tar.gz`, `letsencrypt.tar.gz`).
|
||||||
|
2. `systemctl disable --now nginx`, `systemctl disable --now certbot.timer`.
|
||||||
|
3. Установлен `docker-compose-v2` 2.40.3 (v1 ломался на Docker 28).
|
||||||
|
4. `/srv/elevenlabs/docker-compose.yaml` и `.env` обновлены (бэкапы `.bak-2026-09-20`), добавлены `DOMAIN=proxy.bildme.ru`, `ACME_EMAIL=vasyakrg@gmail.com`.
|
||||||
|
5. Контейнер пересоздан из образа `0.2.0` / `latest`.
|
||||||
|
|
||||||
|
## Проверки (прод)
|
||||||
|
| Проверка | Результат |
|
||||||
|
|----------|-----------|
|
||||||
|
| Сертификат | `CN=proxy.bildme.ru`, issuer Let's Encrypt YE1, до 19.12.2026 |
|
||||||
|
| `https://proxy.bildme.ru/health` | 200 |
|
||||||
|
| `http://62.84.98.250:8082/health` | 200 |
|
||||||
|
| `http://proxy.bildme.ru/health` | 308 → https |
|
||||||
|
| Без `X-Proxy-Token` | 403 `invalid_token` |
|
||||||
|
| IP вне `ALLOWED_CIDR` | 403 `ip_not_allowed` |
|
||||||
|
| `/deepseek/chat/completions` | 401 от DeepSeek (проброс работает, исходный i/o timeout снят) |
|
||||||
|
| `/telegram/`, `/openrouter/`, `/elevenlabs/` | 401 / 200 / 404 от апстримов — проброс работает |
|
||||||
|
| Неизвестный префикс | 404 `unknown_upstream` |
|
||||||
|
| Пересоздание контейнера | сертификат переиспользован из тома, повторного выпуска не было |
|
||||||
|
| Healthcheck | `healthy` |
|
||||||
|
|
||||||
|
## Риски и открытые пункты
|
||||||
|
- **8082 остаётся plain HTTP** — токен и ключи апстримов идут открытым текстом. Клиентов нужно перевести на `https://proxy.bildme.ru`, после чего порт закрыть (ufw на VM сейчас `inactive`).
|
||||||
|
- **Том `caddy_data`** содержит сертификаты и ACME-аккаунт. Его удаление = повторный выпуск и риск упереться в лимиты Let's Encrypt.
|
||||||
|
- **Хостовый nginx остановлен и отключён**, конфиги в бэкапе. Если на VM появятся новые сайты — их конфиг переносится в `Caddyfile`, а не обратно в nginx.
|
||||||
|
- **`certbot.timer` отключён** — старый серт `tg.bildme.ru` больше не обновляется (домен и так живёт на другом сервере).
|
||||||
|
- Локальный каталог `ssl/` с `tls.crt`/`tls.key` удалён — эти файлы не были в git и на проде не монтировались.
|
||||||
Reference in new issue
Block a user