SSH через Tor onion service без відкритих портів
Налаштуйте sshd за Tor onion service без вхідних портів: авторизація v3, firewall і точний порядок змін, щоб не втратити доступ до VPS після збою.
Що змінює SSH через onion service Tor
SSH через onion service Tor дає змогу адмініструвати VPS, який не приймає вхідні з’єднання на жодному порту. Сервер сам встановлює вихідне з’єднання з мережею Tor і підтримує його відкритим. Ваша SSH-сесія проходить назад через це з’єднання, тому на публічній IP-адресі нічого не має приймати з’єднання.
Вплив на журнал помітний одразу. Сервер із публічним SSH-портом щодня отримує тисячі невдалих спроб входу за паролем від сканерів. Перемістіть sshd за onion service і заблокуйте вхідний трафік у firewall — тоді /var/log/auth.log реєструватиме лише сесії, які ви запускали.
Недолік полягає в тому, що tor бере участь у кожній адміністративній сесії. Це daemon у userspace, який після кожного перезавантаження має запуститися та виконати bootstrap, перш ніж ви зможете увійти. Продумайте це до закриття порту, оскільки в разі збою можна втратити доступ до машини, до якої немає фізичного доступу.
Підготуйте спосіб відновлення доступу, перш ніж щось змінювати
Не починайте роботу, доки не матимете способу відновити доступ без використання SSH.
Відкрийте консоль свого провайдера: VNC або serial console у панелі керування. Увійдіть до сервера через неї. Якщо пароль root невідомий, спочатку скиньте пароль root у панелі та перевірте, що він працює. Консоль, яку ви ніколи не тестували, не є способом відновлення доступу.
Наведений нижче порядок має значення. Перед виконанням наступного кроку перевіряйте результат попереднього. Порт 22 має залишатися відкритим, доки onion route не запрацює.
- Встановіть tor і переконайтеся, що він успішно запускається.
- Визначте onion service та прочитайте його адресу.
- Підключіться через onion, доки порт 22 ще відкритий.
- Додайте client authorisation, а потім підключіться ще раз.
- Прив’яжіть
sshdдо loopback і закрийте порт 22. - Перезавантажте сервер, а потім знову підключіться через onion.
Не закривайте поточну SSH-сесію протягом усієї процедури. Встановлена сесія продовжить працювати після зміни firewall, яка заблокувала б нове підключення. Тому вона є вашим першим способом відновлення доступу.
Встановіть tor на сервері
Ubuntu постачає tor у власному репозиторії, але ця збірка часто застаріла. Репозиторій Tor Project містить версію, описану в їхній документації. Додайте його за допомогою команд із посібника з apt-репозиторію.
sudo apt update
sudo apt install -y apt-transport-https wget gpg
wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | sudo tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/nullВведіть /etc/apt/sources.list.d/tor.sources. Suites отримує codename вашого релізу, який виводить lsb_release -cs (noble в Ubuntu 24.04).
Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: noble
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpgsudo apt update
sudo apt install -y tor deb.torproject.org-keyring
sudo journalctl -u tor@default -n 20 --no-pagerЖурнал має завершуватися повідомленням Bootstrapped 100% (done). Якщо він зупинився раніше, tor не може підключитися до мережі. Майже завжди причина полягає в правилі вихідного firewall або суттєво неправильному системному часі.
Назва unit є пасткою. systemctl status tor повідомляє Active: active (exited), навіть коли все працює нормально, оскільки Debian і Ubuntu пакують tor як master unit для кількох екземплярів. Його єдине завдання — підключити фактичний екземпляр. Сам daemon працює як tor@default.service. Використовуйте цю назву для status і journalctl. Команди запуску, зупинки та перезавантаження конфігурації для tor все одно передаються цьому екземпляру, тому sudo systemctl reload tor працює очікувано.
Визначте onion service для порту 22
Додайте два рядки до /etc/tor/torrc.
HiddenServiceDir /var/lib/tor/ssh/
HiddenServicePort 22 127.0.0.1:22Другий рядок вказує tor приймати віртуальний порт 22 на onion-адресі та підключатися до 127.0.0.1:22 на сервері. Tor підключається до sshd через loopback. Саме тому пізніше sshd можна налаштувати так, щоб він більше не прослуховував публічну адресу. Якщо замість цього вказати у другому рядку вебсервер на 127.0.0.1:80, ті самі дві директиви опублікують сайт на onion-адресі. Це корисний другий сервіс, який можна запустити після встановлення tor.
sudo systemctl reload tor
sudo cat /var/lib/tor/ssh/hostnameКоманда виводить 56 символів base32, після яких іде .onion. Ці символи є закодованим представленням публічного ключа сервісу. У цій схемі немає ні центру сертифікації, ні реєстрації імені.
Нехай tor сам створить /var/lib/tor/ssh/. Якщо створити його вручну з неправильним власником або встановити для нього права, ширші за 0700, tor відмовиться його використовувати, а журнал повідомить, що права доступу до каталогу надто широкі. Файли всередині містять ідентичність сервісу: hs_ed25519_secret_key є адресою. Створіть резервну копію цього каталогу з правами 600 і зберігайте копію не на цьому сервері. Якщо втратити її, доведеться отримати нову адресу та змінити конфігурацію на кожному клієнті.
Підключення з робочої станції
На робочій станції потрібен tor client, який не потребує жодного налаштування. У Debian або Ubuntu це sudo apt install -y tor netcat-openbsd. Після цього Tor слухає на 127.0.0.1:9050 як SOCKS5 proxy. SOCKS — це універсальний протокол proxy. Версія 5 може передавати ім’я хоста замість IP-адреси. Саме це тут важливо.
OpenSSH не має власного SOCKS client, тому для підключення потрібна допоміжна програма. Додайте це до ~/.ssh/config.
Host myvps
HostName xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion
User admin
ProxyCommand /usr/bin/nc -X 5 -x 127.0.0.1:9050 %h %p
ServerAliveInterval 30-X 5 вибирає SOCKS5, а -x 127.0.0.1:9050 вказує на локальний tor. %h передає onion-ім’я до tor саме як ім’я, тому tor розпізнає його всередині мережі. Це має бути OpenBSD netcat. GNU netcat не має параметра -X і завершує роботу з помилкою nc: invalid option -- 'X'.
ssh myvpsПерше підключення повільне, оскільки tor спочатку будує circuit. Прийміть fingerprint ключа хоста так само, як і в інших випадках. Надалі звичайне керування ключами SSH застосовується без змін. Змінився транспорт. Автентифікація — ні.
Для одноразового підключення можна не додавати запис до конфігурації: torsocks ssh admin@xxxxx.onion виконує те саме завдання.
Додайте авторизацію клієнта v3
Зараз будь-хто, хто дізнається адресу, може побачити банер SSH і почати підбирати облікові дані. Onion-адреси неможливо перелічити через систему каталогів, тому адреса поводиться як секрет, але може витекти звичайними способами: через історію shell або конфігураційні файли, додані до git-репозиторію. Авторизація клієнта усуває цю проблему. Сервіс публікує свій descriptor у зашифрованому вигляді для ключа клієнта, тому той, хто має лише адресу без ключа, не може навіть знайти сервіс.
Згенеруйте пару ключів x25519 на клієнті. Це pipeline з посібника Tor Project з авторизації клієнта з однією зміною.
openssl genpkey -algorithm x25519 -out /tmp/k1.prv.pem
grep -v " PRIVATE KEY" /tmp/k1.prv.pem | base64 -d | tail --bytes=32 | base32 | sed 's/=//g' > /tmp/k1.prv.key
openssl pkey -in /tmp/k1.prv.pem -pubout | grep -v " PUBLIC KEY" | base64 -d | tail --bytes=32 | base32 | sed 's/=//g' > /tmp/k1.pub.keyУ опублікованій версії цих рядків використовується base64pem -d, якого немає у стандартній інсталяції Ubuntu. Після цього команда завершується помилкою base64pem: command not found. GNU base64 -d декодує те саме тіло PEM, тому використовуйте його.
На сервері встановіть публічний ключ.
sudo install -d -m 700 -o debian-tor -g debian-tor /var/lib/tor/ssh/authorized_clients
echo "descriptor:x25519:PASTE_PUBLIC_KEY_HERE" | sudo tee /var/lib/tor/ssh/authorized_clients/laptop.auth >/dev/null
sudo chown debian-tor:debian-tor /var/lib/tor/ssh/authorized_clients/laptop.auth
sudo systemctl reload torЗчитуються лише файли, що закінчуються на .auth. Збережіть його як laptop.auth.txt, інакше tor проігнорує файл без виведення помилки, а сервіс непомітно залишиться доступним для будь-кого, хто має адресу.
На клієнті встановіть приватний ключ. В Ubuntu daemon tor працює від імені користувача debian-tor і не може читати файли у вашому домашньому каталозі, тому розмістіть каталог у місці, доступному для цього користувача.
sudo install -d -m 700 -o debian-tor -g debian-tor /var/lib/tor/onion_auth
echo "ADDRESS_WITHOUT_DOT_ONION:descriptor:x25519:PASTE_PRIVATE_KEY_HERE" | sudo tee /var/lib/tor/onion_auth/myvps.auth_private >/dev/null
sudo chown debian-tor:debian-tor /var/lib/tor/onion_auth/myvps.auth_private
sudo chmod 600 /var/lib/tor/onion_auth/myvps.auth_privateДодайте ClientOnionAuthDir /var/lib/tor/onion_auth до /etc/tor/torrc клієнта та перезавантажте tor. Якщо ви запускаєте tor від власного користувача, наприклад версію Homebrew у macOS, вкажіть у ClientOnionAuthDir шлях до ~/.tor/onion_auth з правами доступу 0700.
Адреса у цьому файлі складається з 56 символів без суфікса .onion. Після завершення видаліть /tmp/k1.prv.pem і /tmp/k1.prv.key.
Тепер перевірте обидва напрямки. ssh myvps має й надалі підключатися. З машини, на якій немає ключа, та сама адреса має бути недоступною. Така помилка підтверджує, що авторизацію активовано.
Закрийте порт 22 у такому порядку
Спочатку встановіть аварійний захист. Ця команда скасує обидві наведені нижче зміни через fifteen minutes, якщо ви втратите доступ.
sudo systemd-run --on-active=15m --unit=ssh-rescue \
/bin/sh -c 'ufw allow 22/tcp; rm -f /etc/systemd/system/ssh.socket.d/override.conf; systemctl daemon-reload; systemctl restart ssh.socket'Скасуйте його за допомогою sudo systemctl stop ssh-rescue.timer, коли переконаєтеся, що onion-маршрут і далі працює.
Далі забороніть sshd прослуховувати публічну адресу. Ubuntu 24.04 запускає ssh через socket unit, тому ListenAddress у sshd_config ігнорується: сокетом прослуховування керує ssh.socket, а не sshd. Перевірте, який варіант використовується у вашій системі.
systemctl is-enabled ssh.socketЯкщо команда виведе enabled, виконайте sudo systemctl edit ssh.socket і додайте цей фрагмент.
[Socket]
ListenStream=
ListenStream=127.0.0.1:22Порожній ListenStream= очищає значення, успадковане від packaged unit. Якщо не додати цей рядок, ви створите другий listener, водночас зберігши публічний. Це найпоширеніша причина непомітної помилки на цьому кроці.
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
ss -tlnp | grep ':22'ss має показати 127.0.0.1:22 і нічого на 0.0.0.0:22. Якщо ssh.socket було вимкнено, додайте ListenAddress 127.0.0.1 до /etc/ssh/sshd_config.d/10-onion.conf, виконайте sudo systemctl restart ssh, а потім перевірте результат тим самим рядком ss. Цей вивід є підтвердженням в обох випадках.
Потім налаштуйте firewall. Це звичайне керування правилами ufw на VPS. Спочатку виконайте sudo ufw status numbered і видаліть правило SSH, яке буде показано.
sudo ufw status numbered
sudo ufw delete allow OpenSSH
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw status verboseЗалиште вихідний трафік дозволеним. Tor підключається назовні до relay на таких портах, як 443 і 9001. Тому політика за замовчуванням із забороною вихідного трафіку зупинить bootstrap Tor і одночасно усуне єдиний спосіб повторно підключитися. Більшість провайдерів також мають окремий мережевий firewall у панелі керування. Закрийте порт 22 і там, інакше він залишатиметься доступним незалежно від того, що показує ufw.
Якщо на цьому сервері працює Docker, перевірте опубліковані порти перед завершенням роботи. Docker додає власні правила до тих самих таблиць і публікує порти контейнерів безпосередньо в обхід ufw, тому політика заборони в ufw не дає повної картини.
Перезавантажте сервер, перш ніж вважати налаштування надійним
systemctl is-enabled tor@default
sudo rebootЯкщо перша команда не повідомляє, що сервіс увімкнено, виконайте sudo systemctl enable tor@default перед перезавантаженням. Зачекайте дві хвилини, а потім виконайте ssh myvps. Після завантаження Tor має пройти bootstrap, тому onion-адреса починає відповідати через деякий час після запуску самого сервера.
Якщо сервіс так і не відновиться, відкрийте консоль і перегляньте sudo journalctl -u tor@default -b. Там буде виведено синтаксичну помилку torrc або проблему з правами доступу до каталогу. Також можна перевірити зміни в torrc перед їх застосуванням.
sudo -u debian-tor tor --verify-configВартість порівняно з тунелем WireGuard
Порівняно з WireGuard VPN на власному VPS, onion service повільніший і менш передбачуваний. Перед розгортанням чесно оцініть цей компроміс.
Затримка. Клієнтський circuit проходить через три relay, а сторона сервісу додає ще три, тому натискання клавіш проходять приблизно через шість машин, випадково вибраних у різних частинах світу. Під час інтерактивного введення затримка помітна, а копіювання файлів відбувається повільно. WireGuard додає один hop. Перевірте свій випадок за допомогою time ssh myvps 'echo ok', оскільки результат залежить від circuit, який tor побудував цього разу, і змінюється, коли tor будує інший circuit.
Userspace daemon у критичному ланцюжку. WireGuard працює в kernel і запускається разом із мережею. Tor — це процес, який має запуститися, виконати bootstrap і встановити зв’язок із guard relay, перш ніж щось запрацює. Якщо він не запускається, вам доведеться скористатися консоллю провайдера.
Точність годинника. Дескриптори onion service публікуються для певних періодів часу, тому значно неправильний час ламає пошук адреси без зрозумілого повідомлення про помилку. timedatectl має вивести System clock synchronized: yes.
Натомість ви отримуєте захист, який більше не залежить від правильності правила firewall. Немає порту для сканування або банера для зчитування. Адреса сама є public key, тому endpoint підтверджує свою ідентичність ще до початку SSH-сеансу.
На практиці зазвичай використовують обидва варіанти. Використовуйте WireGuard як основний шлях доступу, а onion service залиште як маршрут, який працює навіть тоді, коли конфігурацію WireGuard налаштовано неправильно. Тоді відкритим залишається один UDP-порт, а не публічний SSH-порт. Це не скасовує потреби в зміцненні захисту самого sshd: автентифікація лише за ключами та вхід не під root залишаються важливими, оскільки onion service захищає мережевий шлях і нічого за його межами.
Режими відмови та помилки, які ви побачите
Tor не проходить через Bootstrapped 0%. Вихідний трафік заблокований або системний час значно неправильний. Перевірте політику вихідного трафіку за допомогою sudo ufw status verbose, потім виконайте timedatectl.
systemctl status tor повідомляє active (exited). У Debian та Ubuntu це нормально. Натомість перегляньте tor@default.
Дескриптор не знайдено. Tor повертає розширену помилку SOCKS F0: "Onion Service Descriptor Can Not be Found". Дескриптор ще не опублікований — після перезавантаження це займає деякий час — або tor на сервері не запущений.
F4, "Onion Service Missing Client Authorization". На клієнті немає відповідного .auth_private, який може використати tor. Перевірте, що ClientOnionAuthDir вказано в torrc, каталог має режим 0700, ім’я файлу закінчується на .auth_private, а debian-tor має дозвіл читати цей файл.
F5, "Onion Service Wrong Client Authorization". Приватний ключ не відповідає файлу .auth на сервері. Це спричиняє кінцевий = або зайвий символ нового рядка всередині рядка base32.
nc: invalid option -- 'X'. Замість OpenBSD netcat встановлено GNU netcat. Виконайте sudo apt install -y netcat-openbsd.
Could not resolve hostname. ssh виконав звичайний DNS-запит, але для .onion немає відповіді, тому ProxyCommand не запустився. Шаблон Host у ~/.ssh/config не відповідає введеному вами імені.
Permission denied (publickey). Тунель працює, а tor завершив роботу. Розглядайте це як звичайну проблему permission denied з publickey і не пов’язуйте її з tor.
FAQ
Чи справді onion service означає, що на моєму VPS немає відкритих портів?
Так, якщо sshd прив’язано до 127.0.0.1, а firewall відкидає вхідний трафік. Tor встановлює вихідне TCP-з’єднання з relay, і ваш сеанс проходить через нього у зворотному напрямку. Тому жоден процес на сервері не приймає з’єднання через публічну адресу. Перевірте це за допомогою ss -tlnp на сервері та сканування портів з іншого вузла. Не забудьте про власний network firewall провайдера в панелі керування. Це окремий засіб контролю, не пов’язаний з ufw, і його також потрібно закрити.
Чи достатньо адреси .onion як єдиного захисту для SSH?
Ні. Адреса містить 56 символів, і її не можна вгадати або перебрати через систему каталогів, тому вона поводиться як секрет. Але адреса може потрапити в історію shell і конфігураційні файли. Додайте авторизацію клієнта v3. У такому разі дескриптор сервісу шифрується за допомогою ключа клієнта. Той, хто має лише адресу, отримує розширену помилку F4 і взагалі не досягає sshd.
Що станеться, якщо tor не запуститься після перезавантаження?
Ви повністю втратите доступ через SSH, оскільки onion address буде єдиним способом підключення. Саме тому перед закриттям порту 22 потрібно перевірити консоль провайдера. Tor також потребує часу для bootstrap після запуску системи, тому адреса починає відповідати пізніше, ніж машина відповідає на ping. Якщо адреса взагалі не відповідає, увійдіть через консоль і перегляньте sudo journalctl -u tor@default -b. Там буде зазначено синтаксичну помилку torrc або проблему з правами доступу до /var/lib/tor/ssh.
Чи повільніший SSH через Tor, ніж WireGuard?
Так, і суттєво. З’єднання з onion service проходить приблизно через шість relay, вибраних випадково, тоді як WireGuard використовує один зашифрований перехід безпосередньо до сервера. Введення команд відчувається повільним, а передавання даних займає більше часу. Поширена схема — використовувати WireGuard для щоденної роботи, а onion service залишити як аварійний маршрут, який працює навіть у разі пошкодження конфігурації VPN.