13.10.2026 сайт висел на «Проверяем…» для любой ссылки YouTube: провайдер начал молча глотать ClientHello с SNI youtube.com, youtu.be, ytimg.com, ggpht.com и youtubei.googleapis.com (TCP проходит, TLS молчит; с SNI www.google.com на том же адресе рукопожатие проходит). В списках zapret YouTube не было вовсе. Заведён отдельный список egress-hosts-yt.txt и профиль hostfakesplit_multi:hosts=google.com,vimeo.com:tcp_ts=-1000:tcp_md5:repeats=2 (zapret-multishake.lua) — описано в AGENTS.md вместе с запасными стратегиями и быстрой проверкой. YTG_DISK_QUOTA_MB: 5120 -> 51200. В 5 ГБ влезало два с половиной файла предельного размера, готовый файл могли вытеснить раньше, чем его сохранят. Раздел защищает отдельный порог YTG_MIN_FREE_DISK_MB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
105 lines
5.2 KiB
Desktop File
105 lines
5.2 KiB
Desktop File
[Unit]
|
||
Description=yt-grab — веб-GUI для yt-dlp (yt.zapret.moe)
|
||
After=network-online.target ytgrab-egress-tunnel.service ytgrab-egress-pool.target ytgrab-youtube-ip.service
|
||
Wants=ytgrab-egress-tunnel.service ytgrab-egress-pool.target ytgrab-youtube-ip.service
|
||
Wants=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
# Отдельный системный пользователь, а не codex-pve: весь трафик uid 1000
|
||
# (codex-pve) заворачивает в туннель VPN-замок ccw-vpn (ccw-vpn-lock.service,
|
||
# /etc/ccw-vpn), а всё мимо туннеля сбрасывает. Привязка к <IP_ДЛЯ_YOUTUBE> на
|
||
# vmbr0 под ним даёт «Connection reset by peer» — 29.09.2026 YouTube так и
|
||
# лёг. Доступ к репозиторию — ACL: x на /home/codex-pve, rX на репо,
|
||
# rwX на downloads/ и data/ (setfacl, пакет acl).
|
||
User=ytgrab
|
||
Group=ytgrab
|
||
WorkingDirectory=/home/codex-pve/ytdlp-gui
|
||
|
||
# Домашняя папка примонтирована только на чтение (ProtectHome),
|
||
# а gunicorn пишет туда управляющий сокет — уводим его в приватный /tmp.
|
||
Environment=HOME=/tmp
|
||
Environment=YTG_HOST=127.0.0.1
|
||
Environment=YTG_PORT=8090
|
||
Environment=YTG_TRUST_PROXY=1
|
||
Environment=YTG_MAX_CONCURRENT=32
|
||
Environment=YTG_MAX_FILESIZE_MB=2048
|
||
# Квота держится заметно ниже свободного места на разделе: это
|
||
# гипервизор, и заполнить его корень — значит остановить виртуальные
|
||
# машины, а не просто отдать пользователю ошибку.
|
||
Environment=YTG_DISK_QUOTA_MB=51200
|
||
Environment=YTG_QUIET_ACCESS_LOG=1
|
||
Environment=YTG_EGRESS_PROXY=socks5h://127.0.0.1:18099
|
||
Environment=YTG_EGRESS_POOL=socks5://127.0.0.1:18110-18141
|
||
Environment=YTG_YT_SOURCE_IP=<IP_ДЛЯ_YOUTUBE>
|
||
|
||
# Один воркер: состояние задач держится в памяти процесса.
|
||
# Потоки обслуживают SSE-соединения и параллельные запросы.
|
||
# Потоков заметно больше числа одновременных загрузок: каждое SSE-соединение
|
||
# занимает поток на всё время загрузки, и при 16 потоках сервис подвешивался
|
||
# двумя клиентами. В nginx стоит limit_conn 24 на адрес.
|
||
ExecStart=/home/codex-pve/ytdlp-gui/.venv/bin/gunicorn \
|
||
--workers 1 \
|
||
--threads 64 \
|
||
--timeout 0 \
|
||
--graceful-timeout 30 \
|
||
--bind 127.0.0.1:8090 \
|
||
--access-logfile /dev/null \
|
||
--error-logfile - \
|
||
app:app
|
||
|
||
Restart=on-failure
|
||
RestartSec=5
|
||
|
||
# --- Изоляция ---
|
||
NoNewPrivileges=yes
|
||
PrivateTmp=yes
|
||
ProtectSystem=strict
|
||
ProtectHome=read-only
|
||
ReadWritePaths=/home/codex-pve/ytdlp-gui/downloads
|
||
ReadWritePaths=/home/codex-pve/ytdlp-gui/data
|
||
ProtectKernelTunables=yes
|
||
ProtectKernelModules=yes
|
||
ProtectControlGroups=yes
|
||
RestrictSUIDSGID=yes
|
||
RestrictNamespaces=yes
|
||
LockPersonality=yes
|
||
|
||
# --- Запрет исходящих во внутреннюю сеть ---
|
||
# Проверка адреса в приложении принципиально не закрывает DNS rebinding
|
||
# (yt-dlp резолвит имя заново и сам ходит по редиректам), поэтому запрет
|
||
# ставится на уровне ядра. Хост — гипервизор: во внутренней сети живут
|
||
# его API и виртуальные машины.
|
||
# Здесь НЕТ IPAddressAllow=any, и это существенно: с ним запреты ниже
|
||
# фактически не работали — проверено, Proxmox API на 10.20.0.1:8006 и
|
||
# соседняя ВМ оставались доступны. Когда список состоит только из
|
||
# запретов, systemd пропускает всё остальное, и внешняя сеть с DNS
|
||
# продолжают работать (тоже проверено).
|
||
#
|
||
# Петля (127.0.0.0/8, ::1) сознательно НЕ закрыта: фильтр systemd не
|
||
# различает направление, и запрет петли обрывает входящие соединения от
|
||
# nginx к этому же сервису — проверено, слушатель становится недоступен
|
||
# снаружи и сайт ложится. Поэтому службы на 127.0.0.1 остаются достижимы;
|
||
# закрыть их можно, только переведя связку nginx→приложение на
|
||
# unix-сокет.
|
||
IPAddressDeny=10.0.0.0/8
|
||
IPAddressDeny=172.16.0.0/12
|
||
IPAddressDeny=192.168.0.0/16
|
||
IPAddressDeny=169.254.0.0/16
|
||
IPAddressDeny=100.64.0.0/10
|
||
IPAddressDeny=fc00::/7
|
||
IPAddressDeny=fe80::/10
|
||
|
||
# --- Ресурсы хоста ---
|
||
# Сервис делит гипервизор с виртуальными машинами: ffmpeg при
|
||
# перекодировании иначе забирает все ядра у соседей.
|
||
CPUWeight=20
|
||
IOWeight=20
|
||
Nice=10
|
||
|
||
# --- Лимиты ресурсов ---
|
||
MemoryMax=4G
|
||
TasksMax=2048
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|