add: Прозрачный прокси контейнера через Shadowsocks и tun2socks (03)
This commit is contained in:
@@ -50,7 +50,7 @@ Traefik на k3s и все еще проходдит через VIP-адрес K
|
||||
|
||||
Как-то так:
|
||||
```text
|
||||
Интернет Интернет
|
||||
Интернет для upload Интернет для прослушивания
|
||||
▲ ▲
|
||||
│ │
|
||||
│ │
|
||||
@@ -58,15 +58,15 @@ Traefik на k3s и все еще проходдит через VIP-адрес K
|
||||
│ VPN (Shadowsocks Server) │ │ (SSL)
|
||||
└──────────────────────▲───────┘ │
|
||||
╚═════════════════════╗ │
|
||||
┌──▲────▲──┐
|
||||
┌──╨────┴──┐
|
||||
│ Роутер │
|
||||
└──▲────▲──┘
|
||||
║ │
|
||||
для скачивания ║ └──────────────┐
|
||||
(канал-VPN) ║ │
|
||||
для upload ║ └──────────────┐
|
||||
(VPN-тоннель) ║ │
|
||||
···Docker Compose (на Synology)································ ║ ·············· │
|
||||
: ║ : │
|
||||
: ┌────────────────┐ ┌───────────────┐ ┌─────────▲──────────┐ : ▲
|
||||
: ┌────────────────┐ ┌───────────────┐ ┌─────────╨──────────┐ : ▲
|
||||
: │ Audiobookshelf ├─────►│ tun2socks ├────────►│ shadowsocks/SOCKS5 │ : │
|
||||
: └────────────────┘ └───────┬───────┘ └────────────────────┘ : │
|
||||
: │ для прослушивания : │
|
||||
@@ -77,3 +77,163 @@ Traefik на k3s и все еще проходдит через VIP-адрес K
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
Почему так сложно?
|
||||
|
||||
- Во-первых, на VPS/VDS, где я держу свои проекты, уже был настроен Shadowsocks-сервер (Outline), Не для обхода
|
||||
блокировок, а для безопасного доступа и администрирования (а еще для того чтоб посещать Госуслуги и другие ресурсы,
|
||||
находясь в поездках за границей). Поэтому было логично использовать его.
|
||||
- Во-вторых, для Docker не существует полноценного VPN-клиента Shadowsocks. Есть только прокси-клиенты (ss-local),
|
||||
которые предоставляют SOCKS5 интерфейс.
|
||||
- При этом, и это в-третьих, Audiobookshelf не умеет работать с SOCKS5. Ему нужен настоящий HTTP, причем из-за
|
||||
встроенной в Audiobookshelf защиты от SSRF атак он не может работать даже с HTTP-прокси, который находится
|
||||
в Docker сети (например, Privoxy). Ему нужно сделать прозрачную сеть через TUN интерфейс -- тогда он будет
|
||||
доволен.
|
||||
- Для этого, в-четвертых, нужно сделать так, чтобы весь трафик контейнера Audiobookshelf автоматически
|
||||
шел через единственный контейнер (tun2socks), который будет форвардить и http, и https через Shadowsocks (для
|
||||
скачивания подкастов) и отдавать http-трафик на порт 8000 для прослушивания через Nginx. Именно такая схема
|
||||
не будет ломать работу SSRF-фильтра и защитит от этого тип атаки (_можно было, конечно, откатить Audiobookshelf
|
||||
до древней версии 2.6.0, где дыра SSRF еще была, но это не самое безопасное решение, да и на DockerHub уже нет
|
||||
этой версии_).
|
||||
|
||||
### Старый манифест Docker
|
||||
|
||||
В Docker Station на Synology у меня было:
|
||||
```yml
|
||||
version: "3.8"
|
||||
services: audiobookshelf:
|
||||
image: advplyr/audiobookshelf:latest
|
||||
restart: always
|
||||
ports:
|
||||
- 8000:80
|
||||
volumes:
|
||||
- ./config:/config
|
||||
- ./metadata:/metadata
|
||||
- /volume1/music/_podcasts:/podcasts
|
||||
- /volume1/music/_audio_books:/audiobooks
|
||||
environment:
|
||||
- TZ=Europe/Moscow
|
||||
```
|
||||
|
||||
Тут, вроде все просто. На Synology есть папка `/volume1/music/` уже с завода. В ней я создал папки `_podcasts`
|
||||
и `_audio_books` для хранения книг и подкастов, и смонтировал эти папки в контейнер. Также добавил папки `config`
|
||||
и `metadata` для хранения конфигурации и метаданных. Эти папки создадются при первом запуске контейнера, и будут
|
||||
расположены рядом `compose.yml` (в каталоге `/volume1/docker/audiobookshelf/`... папка `/volume1/docker/` тоже
|
||||
будет создана при установке приложения Docker Station на Synology... нам нужно только создать каталог `audiobookshelf/`
|
||||
и и выбрать ее при создании проекта в Docker Station).
|
||||
|
||||
Порт 8000 проброшен наружу и Nginx на хосте Orange Pi 5 Plus проксирует на этот порт, добавляет SSL и так далее.
|
||||
|
||||
### Новая схема и манифест для Docker Station
|
||||
|
||||
Теперь у нас будет три контейнера (и определённая зависимость между ними):
|
||||
|
||||
```yml
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
# [1] Shadowsocks клиент для подключения к Outline/VPS (предоставляет SOCKS5 на порту 1080)
|
||||
ss-ru:
|
||||
image: shadowsocks/shadowsocks-libev
|
||||
container_name: ss-ru
|
||||
restart: unless-stopped
|
||||
command: >
|
||||
ss-local
|
||||
-s [IP-адрес Outline/VPS]
|
||||
-p [порт Outline/VPS]
|
||||
-k [пароль Outline/VPS]
|
||||
-m [метод шифрования]
|
||||
-l 1080
|
||||
-b 0.0.0.0
|
||||
|
||||
# [2] Privoxy — HTTP-прокси для Node.js, форвардит через ss-ru
|
||||
tun2socks:
|
||||
image: xjasonlyu/tun2socks
|
||||
container_name: tun2socks
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- /dev/net/tun
|
||||
ports:
|
||||
- "8000:80"
|
||||
command: >
|
||||
-device tun://tun0
|
||||
-proxy socks5://ss-ru:1080
|
||||
depends_on:
|
||||
- ss-ru
|
||||
|
||||
# [3] Audiobookshelf, использующий Privoxy для доступа к интернету
|
||||
audiobookshelf:
|
||||
image: advplyr/audiobookshelf:2.28.0
|
||||
container_name: audiobookshelf
|
||||
restart: always
|
||||
network_mode: "service:tun2socks"
|
||||
volumes:
|
||||
- ./config:/config
|
||||
- ./metadata:/metadata
|
||||
- /volume1/music/_audio_books:/audiobooks
|
||||
- /volume1/music/_podcasts:/podcasts
|
||||
environment:
|
||||
- TZ=Europe/Moscow
|
||||
depends_on:
|
||||
tun2socks:
|
||||
condition: service_started
|
||||
```
|
||||
|
||||
Что тут происходит:
|
||||
|
||||
**Первым стартует** контейнер `ss-ru`. Он ни от кого не зависит. Он подключается к моему Outline-серверу и предоставляет
|
||||
SOCKS5-прокси на порту `1080`.
|
||||
|
||||
Где брать параметры для подключения к Outline/VPS? В панели Outline Manager "Add new Key". Она предоставит строку вида:
|
||||
`ss://[зашифрованный-base64-ключ--метод-шифрования:пароль]@[IP-адрес Outline/VPS]:[порт Outline/VPS]/?outline=1`.
|
||||
Параметры `[IP-адрес Outline/VPS]` и `[порт Outline/VPS]` нужно взять непосредственно из этой строки. Метод шифрования
|
||||
и пароль нужно расшифровать из первой части строки (часть строки между `ss://` и до `@`). Например, командой
|
||||
в терминале:
|
||||
```shell
|
||||
echo "Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpDYVF6OERMRDVHd09meTRvVVk1TmxK" | base64 -d
|
||||
```
|
||||
|
||||
Получим строку вида `chacha20-ietf-poly1305:пароль`. Таким образом `[метод шифрования]` — это `chacha20-ietf-poly1305`,
|
||||
а `[пароль Outline/VPS] — это `пароль`.
|
||||
|
||||
**Вторым стартует** контейнер `tun2socks`. Он зависит от `ss-ru`, так что гарантированно запустится после него. Он
|
||||
использует `ss-ru` как SOCKS5-прокси и создает TUN-интерфейс `tun0` внутри контейнера. Так же он предоставляет
|
||||
HTTP-интерфейс на порту 80 внутри нашего проекта Docker Station (с него будет отвечать Audiobookshelf) который
|
||||
проброшен наружу как 8000).
|
||||
|
||||
Контейнер tun2socks использует системный TUN-интерфейс Synology (`/dev/net/tun`). Поэтому контейнеру нужны права
|
||||
и доступ к этому устройству. Это достигается через:
|
||||
```yml
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- /dev/net/tun
|
||||
```
|
||||
|
||||
На Synology (да и многих Linux) TUN-интерфейс `/dev/net/tun` обычно закрыт. Нужно будет разрешить доступ к нему:
|
||||
```bash
|
||||
# Проверяем, что TUN доступен
|
||||
ls /dev/net/tun
|
||||
# Если выдаёт "/dev/net/tun: no such device", то нужно создать устройство
|
||||
sudo modprobe tun
|
||||
# И снова проверить, что устройство появилось
|
||||
ls /dev/net/tun
|
||||
# Должно вывести: /dev/net/tun
|
||||
```
|
||||
|
||||
| Заметим |
|
||||
| ------- |
|
||||
| Я пробовал други решения: (1) `Privoxy` -- Проблемы: axios внутри Audiobookshelf плохо работает с proxy, ломаются редиректы,SSRF фильтр, сами RSS загружаются, но SSRF будет блокировать запросы к iTunes, а, значит, не будут получаться метаданные, а без метаданных и mp3-файлы не скачиваются. (2) `redsocks` -- Проблемы: нестабильный iptables redirect (на Synology это вообще не работает, похоже), падение самого redsocks, сложная настройка NAT внутри Docker.
|
||||
|
||||
**Третьим стартует** контейнер `audiobookshelf`. В нем почти все по старому. Но теперь он зависит от `tun2socks`,
|
||||
так что гарантированно запустится после него. Кроме того у него теперь нет проброса портов `8000:80` (они у нас
|
||||
теперь в контейнере tun2socks). Вместо этого у него `network_mode: "service:tun2socks"`. Это значит, что он будет
|
||||
использовать сетевой стек контейнера tun2socks. В результате весь его трафик будет идти через TUN-интерфейс
|
||||
Дальше уже `tun2socks` определит что с ним делать. Если трафик пришел снаружи, с порта 8000, то он попадёт
|
||||
в Audiobookshelf, как и раньше. Если же сам Audiobookshelf начнет что-то скачивать, то запрос уйдет через
|
||||
TUN-интерфейс, попадет в `tun2socks`, который отфорвардит его через SOCKS5-прокси `ss-ru` на Outline/VPS
|
||||
(на внешнем хостинге).
|
||||
|
||||
## Запуск и проверка
|
||||
|
||||
|
||||
Reference in New Issue
Block a user