Перейти к содержанию

SOCKS5 без Docker и без VPN: собираем прокси на сервере тремя разными способами

Опубликовано
  • Админы
Свой SOCKS5 на голом сервере

Docker есть не везде и не всегда уместен, а поднимать полноценный VPN ради одного приложения — стрельба из пушки по воробьям. Между этими крайностями лежит SOCKS5: протокол без шифрования и без виртуальных интерфейсов, который просто принимает от программы адрес назначения и ходит туда вместо неё. Понимают его все — браузеры через расширения, curl, git, Telegram, Python-скрипты, исходящие в sing-box и Xray.

Интересно то, что на обычном Linux-сервере эту задачу решают три совершенно разных инструмента, и выбор между ними определяет всё остальное: где будет слушать порт, чем проверяется пароль, куда пойдут логи. Один вариант вообще не требует ставить что-либо на сервер — там достаточно уже работающего sshd.

Разберём все три с рабочими конфигами, systemd-юнитами, правилами файрвола и проверкой на утечку DNS. И отдельно поговорим о том, почему прокси без пароля перестаёт быть вашим примерно за сутки — это не преувеличение, а наблюдаемое поведение сканеров.

Матрица выбора: ssh -D, Dante, 3proxy
Схема на основе man ssh(1), danted.conf(5) и README 3proxy

ℹ️ Справка

Кому это нужно. Есть VPS в нужной стране и SSH-доступ к нему. Хочется, чтобы отдельные программы ходили в сеть через него — без VPN на всю машину, без изменения маршрутов, без прав администратора на клиенте. Всё остальное — детали реализации.


Вариант 1. ssh -D: тридцать секунд и ни одного конфига

Клиент OpenSSH умеет быть SOCKS-сервером сам. Man-страница формулирует это прямо: «Specifies a local "dynamic" application-level port forwarding… Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server».

Ключевой момент, который часто понимают наоборот: порт слушает ваша локальная машина, а не сервер. Сервер только выполняет исходящие соединения. Никакого демона на VPS ставить не надо — там достаточно обычного sshd.

ssh -D 127.0.0.1:1080 -N -C user@vps.example.com

Разбор:

ФлагЧто делает
-D 127.0.0.1:1080поднять SOCKS-сервер на локальном порту 1080, слушать только петлю
-N«Do not execute a remote command» — не запускать шелл, только форвардинг
-Cсжатие всего трафика соединения; полезно на узком канале, вредно на быстром
-fуйти в фон (для ручного запуска; для systemd не нужен)

⚠️ Осторожно

Адрес в -D писать обязательно. ssh -D 1080 в большинстве сборок слушает только localhost, но поведение зависит от GatewayPorts и параметров сборки — и в момент, когда вы решите «пусть с ноутбука жены тоже ходит» и добавите -D 0.0.0.0:1080, у вас появится SOCKS-прокси без единого пароля, доступный всей локальной сети. Для доступа с других машин правильнее прокинуть порт ещё раз, а не открывать его.

Чтобы туннель не умирал

Голый ssh -D разваливается от любого обрыва. Лечится двумя способами, и они дополняют друг друга.

Первый — заставить сам SSH замечать, что связи нет. Второй — перезапускать процесс. Man autossh(1) прямо рекомендует первый: «you may wish to explore using the ServerAliveInterval and ServerAliveCountMax options to have the SSH client exit if it finds itself no longer connected to the server. In many ways this may be a better solution than the monitoring port».

Поэтому в связке с autossh мониторинговый порт отключают (-M 0 — «Setting the monitor port to 0 turns the monitoring function off, and autossh will only restart ssh upon ssh's exit»), а живучесть вешают на keepalive:

# /etc/systemd/system/socks-tunnel.service
[Unit]
Description=SOCKS5 через SSH к vps.example.com
After=network-online.target
Wants=network-online.target

[Service]
User=proxyuser
Environment=AUTOSSH_GATETIME=0
ExecStart=/usr/bin/autossh -M 0 -N -T \
  -o "ServerAliveInterval=15" \
  -o "ServerAliveCountMax=3" \
  -o "ExitOnForwardFailure=yes" \
  -o "StrictHostKeyChecking=yes" \
  -i /home/proxyuser/.ssh/id_ed25519 \
  -D 127.0.0.1:1080 user@vps.example.com
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

AUTOSSH_GATETIME=0 здесь не косметика: по умолчанию autossh считает соединение успешным только после 30 секунд жизни, а с нулём ещё и игнорирует провал первого запуска — то, что нужно при старте системы, когда сеть могла подняться на секунду позже.

ExitOnForwardFailure=yes — тоже не мелочь. Без него ssh спокойно поднимет соединение, на котором порт 1080 занят кем-то другим, и вы будете долго гадать, почему прокси «работает», но ходит не туда.

✅ Как правильно

Когда этого хватает. Один пользователь, один ноутбук, доступ по SSH-ключу уже настроен. Аутентификация в SOCKS не нужна вовсе: чтобы воспользоваться прокси, надо иметь доступ к localhost вашей машины, а он и так есть только у вас. Это самая безопасная конфигурация из трёх — просто потому, что снаружи ничего не слушает.


Вариант 2. Dante: демон, который знает про системных пользователей

Dante (sockd) — эталонная реализация SOCKS от Inferno Nettverk. Текущая версия — 1.4.4; в Debian 13 и Ubuntu пакет называется dante-server, конфиг лежит в /etc/danted.conf (upstream по умолчанию использует /etc/sockd.conf — не путайтесь при чтении официальной документации).

apt update && apt install -y dante-server

Минимальный рабочий конфиг с паролем и ограничением по подсети:

# /etc/danted.conf

logoutput: /var/log/danted.log

# на каком адресе слушаем клиентов
internal: 0.0.0.0 port = 1080
# с какого интерфейса уходим наружу
external: eth0

# от чьего имени работать после старта
user.privileged: root
user.notprivileged: nobody

# метод аутентификации клиента SOCKS
socksmethod: username

# ── правила уровня «кому вообще можно подключиться»
client pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    log: error connect disconnect
}

# ── правила уровня «что можно делать внутри сессии»
socks pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    command: connect
    socksmethod: username
    user: socksuser
    log: error connect
}

Два уровня правил — главная особенность Dante, и на ней спотыкаются чаще всего. client решает, принимать ли TCP-соединение вообще. socks решает, что разрешено делать уже внутри установленной SOCKS-сессии. Пропустили socks pass — клиент подключится и получит отказ на первый же запрос.

Значения, которые стоит знать по имени:

ДирективаДопустимые значения (по danted.conf(5))
socksmethodnone, username, gssapi, pam.any, pam.address, pam.username, rfc931, bsdauth
commandbind, connect, udpassociate, bindreply, udpreply
logconnect, disconnect, data, error, ioop, tcpinfo
logoutputsyslog[/facility], stdout, stderr, имя файла или их комбинация
external.rotationnone (по умолчанию), route, same-same

socksmethod: username означает проверку по системной базе пользователей. Заводим пользователя, которому нечего делать в системе:

useradd -r -s /usr/sbin/nologin socksuser
passwd socksuser

⛔ Так делать нельзя

Не оставляйте socksmethod: none в конфиге, который слушает 0.0.0.0. Это ровно та конфигурация, которую сканеры находят быстрее всего: открытый SOCKS5 на 1080 порту — стандартная цель массовых сканов. Если аутентификация мешает (например, клиент её не умеет), закрывайте доступ на уровне client pass { from: } и файрвола — но не оставляйте открытым и то, и другое.

Ограничение по источнику пишется прямо в правиле:

client pass {
    from: 203.0.113.10/32 to: 0.0.0.0/0
    log: error connect
}
client block {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    log: connect error
}

Порядок важен: правила проверяются сверху вниз, первое совпавшее выигрывает. Явный block в конце — хорошая привычка, даже если поведение по умолчанию и так «запретить».

Запуск и проверка:

systemctl enable --now danted
systemctl status danted
tail -f /var/log/danted.log

Вариант 3. 3proxy: свои пользователи и ACL без системных учёток

3proxy — один бинарник на C, живущий с начала двухтысячных. Последний релиз — 0.9.8 от 7 августа 2024 года; в нём, помимо прочего, появился IMAPv4-прокси и поддержка STARTTLS. Собирается из исходников или ставится готовым deb/rpm из релизов на GitHub.

# сборка из исходников
git clone https://github.com/3proxy/3proxy
cd 3proxy
ln -s Makefile.Linux Makefile
make
make install

Конфиг — последовательный, а не декларативный: директивы применяются по мере чтения файла, и порядок строк меняет смысл.

# /etc/3proxy/3proxy.cfg

# ── DNS: свои резолверы и кэш, чтобы не дёргать систему на каждый запрос
nserver 1.1.1.1
nserver 9.9.9.9
nscache 65536

# ── логи с ежедневной ротацией, flush после каждой записи
log /var/log/3proxy/3proxy.log D
logformat "- +_L%t.%. %N.%p %E %U %C:%c %R:%r %O %I %h %T"
rotate 30

# ── от кого работать после старта (числовые uid/gid своего пользователя)
setgid 65534
setuid 65534

# ── лимиты
maxconn 200

# ── пользователи: логин:тип_пароля:пароль
users socksuser:CL:StrongPassHere

# ── аутентификация: strong = обязательный логин/пароль
auth strong

# ── ACL: разрешаем только известному пользователю с известной подсети
allow socksuser 203.0.113.0/24
deny *

# ── и только теперь поднимаем сервис
socks -p1080 -i0.0.0.0 -e198.51.100.7

Что здесь важно понимать:

  • auth strong требует логин и пароль. Есть ещё auth none (без проверки) и auth iponly (только по IP) — и первое в сочетании с -i0.0.0.0 даёт открытый прокси.
  • allow / deny идут после auth и до socks. Строка socks — это точка, где сервис начинает слушать; всё, что вы объявите после неё, к этому сервису уже не применится.
  • -i — адрес, на котором слушаем; -e — адрес, с которого уходим наружу. На сервере с несколькими IP -e решает, каким адресом вы «светите».
  • CL в строке users означает пароль открытым текстом. Для продакшена лучше CR (crypt) — тогда в конфиге лежит хеш: users socksuser:CR:$1$....

📌 Заметка

Порты по умолчанию у 3proxy: SOCKS — 1080, HTTP-прокси — 3128, FTP — 21, POP3 — 110, SMTP — 25. Если в конфиге не указать -p, поднимется 1080. Это же значение по умолчанию у Dante и у большинства образов — то есть первое, что просканируют.

systemd-юнит:

# /etc/systemd/system/3proxy.service
[Unit]
Description=3proxy tiny proxy server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/3proxy /etc/3proxy/3proxy.cfg
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/log/3proxy

[Install]
WantedBy=multi-user.target

SIGUSR1 — штатный сигнал перечитывания конфига, перезапуск не нужен. Директивы ProtectSystem/NoNewPrivileges стоят бесплатно и заметно сужают последствия, если в прокси когда-нибудь найдут дыру.


Файрвол: не один рубеж, а три

Правило прокси и правило файрвола решают разные задачи, и заменять одно другим — плохая идея.

# nftables: пускаем на 1080 только известную подсеть
nft add rule inet filter input tcp dport 1080 ip saddr 203.0.113.0/24 accept
nft add rule inet filter input tcp dport 1080 drop
# ufw — то же самое
ufw allow from 203.0.113.0/24 to any port 1080 proto tcp
ufw deny 1080/tcp

🔒 Безопасность

Почему открытый прокси — проблема именно владельца сервера. Через ваш SOCKS5 наружу уходят чужие соединения с вашего IP. Спам, брутфорс чужих панелей, сканирование, посещение того, за что придёт abuse-жалоба, — в логах пострадавшей стороны будет ваш адрес. Хостер получает жалобу и, в лучшем случае, просит объясниться; в худшем — блокирует машину без предупреждения. Плюс канал и лимит трафика: 1080-й порт без пароля находят массовые сканеры, и «бесплатный» прокси очень быстро становится популярным.

Минимальный набор, который стоит считать обязательным:

  1. Аутентификация всегда, даже «на пару часов для теста».
  2. Ограничение по IP там, где источник известен, — на уровне и прокси, и файрвола.
  3. Логи с датой, IP и пользователем, и хотя бы раз в неделю — взгляд в них.
  4. Нестандартный порт как косметика поверх пунктов 1–3, а не вместо них.

Проверка: пять команд и одна ловушка с DNS

# 1. Порт вообще слушает и кем?
ss -tlnp | grep 1080

# 2. Простейшая проверка без авторизации
curl -x socks5h://127.0.0.1:1080 https://ifconfig.co

# 3. С логином и паролем
curl -x socks5h://socksuser:StrongPassHere@vps.example.com:1080 https://ifconfig.co

# 4. То же самое отдельными флагами
curl --socks5-hostname vps.example.com:1080 -U socksuser:StrongPassHere https://ifconfig.co

# 5. Убедиться, что снаружи порт закрыт (запускать с ДРУГОЙ машины)
nc -vz vps.example.com 1080

Теперь про ловушку. У curl есть два очень похожих флага, и разница между ними — это разница между «провайдер видит ваши домены» и «не видит».

socks5 против socks5h
Схема на основе таблицы схем прокси из everything.curl.dev

Официальная документация curl приводит таблицу без двусмысленностей: для SOCKS 5 имя резолвит сам curl, для SOCKS 5h — прокси. Соответственно:

  • --socks5 и схема socks5:// — DNS-запрос уходит с вашей машины. Соединение к сайту идёт через прокси, но кто именно вы открываете — знает ваш резолвер и все, кто видит его трафик.
  • --socks5-hostname и схема socks5h:// — curl отдаёт прокси само имя домена, и резолвит его сервер.

❗ Главное

Если прокси нужен для обхода DNS-фильтрации или просто чтобы не отдавать список посещённых доменов локальному резолверу — используйте только socks5h:// (или --socks5-hostname). Схема socks5:// в этом сценарии бесполезна: адрес вы получите тот же самый подменённый, и уйдёте по нему через прокси.

То же самое касается настроек в клиентах: в Firefox нужен включённый «Proxy DNS when using SOCKS v5», в sing-box и Xray у исходящего типа socks за это отвечает поле, отдающее домен вместо IP.

Проверить, куда реально ушёл DNS, проще всего на самом сервере: запустите tcpdump -i any port 53 на прокси и сделайте один запрос с клиента. Видите запрос — резолвит сервер, всё правильно. Не видите — резолвит клиент, и вы, скорее всего, забыли букву h.


Что выбрать в итоге

Если доступ нужен вам одному и SSH-ключ уже настроен — берите ssh -D с autossh. Это единственный вариант, при котором на сервере не появляется нового слушающего порта, а значит, и новой поверхности атаки.

Если прокси нужен как постоянный сервис для нескольких человек и вы уже держите системных пользователей — Dante, у него самая внятная модель правил и подробные логи.

Если хочется своих пользователей отдельно от системных, гибких ACL по времени и подсетям, а заодно HTTP-прокси на том же демоне — 3proxy.

Общее для всех трёх: пароль обязателен, доступ по IP ограничен, логи читаются. Прокси, который вы подняли «на вечер попробовать» и забыли, живёт годами — и всё это время отвечает вашим IP-адресом.


Источники

💬 Вопрос к сообществу

А чем пользуетесь вы и почему? Отдельно интересно про Dante: кто-нибудь довёл до рабочего состояния pam.username вместо простого username — и стоило ли оно возни с PAM-стеком?

Featured Replies

No posts to show

Последние посетители 0

  • Ни одного зарегистрированного пользователя не просматривает данную страницу
Яндекс.Метрика

Account

Navigation

Поиск

Поиск

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.