SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-13

Как создать onion-сайт на своем VPS

Пошаговое руководство по настройке v3 onion-сервиса на Ubuntu с использованием Tor и Nginx. Узнайте, как привязать сервер к loopback и исключить утечки данных через публичный IP.

Что вы создаете

Onion-сайт — это обычный веб-сервер, который отвечает на запросы только через сеть Tor. Установите tor, добавьте две строки в /etc/tor/torrc, узнайте адрес, который сгенерировал tor, и привяжите nginx к 127.0.0.1, чтобы сервер не отвечал на запросы по публичному IP-адресу. Установка занимает десять минут. Остальная часть этого руководства посвящена предотвращению утечек, так как onion-сайты чаще всего терпят неудачу из-за того, что их собственная конфигурация прямо указывает на оператора.

Tor изначально расшифровывался как "the onion router" (луковый маршрутизатор), а onion-сервис — это сервис, доступный только через эту сеть. Адрес третьей версии состоит из 56 символов, за которыми следует .onion. Эти символы представляют собой ed25519 публичный ключ сервиса, контрольную сумму и байт версии, закодированные в base32. Адреса второй версии (16 символов) были удалены из сети в 2021 году, поэтому всё, что вы создаете сегодня, является v3. Адрес и есть ключ, что влечет за собой два последствия. Соединение шифруется и проходит сквозную аутентификацию без участия центра сертификации, а потеря файла ключа означает безвозвратную потерю адреса.

Ваш сервер никогда не принимает входящие соединения. Tor выбирает несколько ретрансляторов в качестве точек входа (introduction points), загружает подписанный дескриптор на серверы каталогов и встречается с каждым посетителем на ретрансляторе встречи (rendezvous relay), который выбрал сам посетитель. Все эти соединения являются исходящими для вашего сервера. Вам не нужно открывать порты или публиковать DNS-записи.

Установка Tor из репозитория Tor Project

В Ubuntu пакет tor входит в репозиторий universe, но его версия остается близкой к той, что была актуальна на момент заморозки релиза. Собственный репозиторий Tor Project содержит текущую стабильную версию, что необходимо для программного обеспечения, от которого зависит анонимность вашего адреса.

sudo apt update
sudo apt install -y apt-transport-https gnupg wget
KEYURL=https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc
wget -qO- "$KEYURL" | gpg --dearmor | sudo tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/null

Запись в репозитории использует формат deb822, а Suites должен соответствовать кодовому имени вашего дистрибутива Ubuntu. Считайте его из файла /etc/os-release, вместо того чтобы вводить вручную: неверное кодовое имя приведет к тому, что репозиторий будет успешно разрешаться, но не будет содержать пакетов для вашего релиза.

. /etc/os-release
sudo tee /etc/apt/sources.list.d/tor.sources >/dev/null <<EOF
Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: $VERSION_CODENAME
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpg
EOF
sudo apt update
sudo apt install -y tor deb.torproject.org-keyring

Пакет deb.torproject.org-keyring поддерживает актуальность ключа подписи, поэтому ротация ключей не нарушит работу apt update в будущем. Проверьте, что tor запустился и установил соединение с сетью:

tor --version
sudo journalctl -u tor@default -n 20

Журнал должен заканчиваться сообщением Bootstrapped 100% (done): Done. Если tor завис на этапе Bootstrapped 10%, значит, отсутствует исходящий маршрут. Проверьте сетевой брандмауэр провайдера и собственные правила исходящего трафика: sudo ufw status verbose должен показывать allow (outgoing) в качестве шлюза по умолчанию.

Далее важны два имени. Пакет запускает tor от имени пользователя debian-tor, а работающий юнит называется tor@default.service, так как tor.service в Debian и Ubuntu является оберткой для экземпляра службы. Запрашивайте статус и логи по имени экземпляра, чтобы всегда получать данные о реальном процессе.

Настройка onion-сервиса в torrc

Добавьте две строки в /etc/tor/torrc:

HiddenServiceDir /var/lib/tor/onion_site/
HiddenServicePort 80 127.0.0.1:8080

HiddenServiceDir — это каталог, в котором Tor хранит ключи и адрес для данного сервиса. Не создавайте его самостоятельно. Tor создаст его при запуске с необходимыми правами доступа и владельцем. Если вы создадите этот каталог от имени root, это приведет к первой ошибке из списка ниже.

HiddenServicePort состоит из двух частей, и их перепутывание — самая частая ошибка. Первое число — это порт, к которому подключается посетитель внутри туннеля, поэтому 80 — это стандарт, который ожидают пользователи, и нет причин его менять. Вторая часть — это локальный адрес, на который Tor перенаправляет трафик. Простая запись HiddenServicePort 80 перенаправляет трафик на 127.0.0.1:80. Указание полного адреса и использование высокоуровневого порта позволяет избежать конфликтов onion-хоста с любыми сервисами, уже слушающими порт 80.

sudo systemctl restart tor@default
sudo ls -l /var/lib/tor/onion_site/

В каталоге должны находиться hostname, hs_ed25519_public_key, hs_ed25519_secret_key и пустой каталог authorized_clients.

Чтение вашего .onion адреса

sudo cat /var/lib/tor/onion_site/hostname

Вы получите одну строку: 56 символов в кодировке base32 и .onion. Эта строка является полным идентификатором сайта. Никто не назначает его, никто не может его передать, и никто не может отобрать его, пока у вас есть файл ключа. Скопируйте его сейчас, так как он потребуется для каждой конфигурации ниже. В остальной части этого руководства он обозначается как <your-address>.onion.

Обслуживание сайта через nginx, привязанный к 127.0.0.1

sudo apt install -y nginx
sudo install -d -m 755 /srv/onion

Напишите /etc/nginx/sites-available/onion:

server {
    listen 127.0.0.1:8080;
    server_name <your-address>.onion;

    root /srv/onion;
    index index.html;

    server_tokens off;
    etag off;
    access_log off;
    error_log /var/log/nginx/onion.error.log error;
}
echo '<h1>hello from the onion</h1>' | sudo tee /srv/onion/index.html
sudo ln -s /etc/nginx/sites-available/onion /etc/nginx/sites-enabled/onion
sudo nginx -t
sudo systemctl reload nginx

Теперь проверьте два условия с сервера. Первое: nginx отвечает на onion-имя, что соответствует заголовку Host, который будет отправлять Tor:

curl -s -H 'Host: <your-address>.onion' http://127.0.0.1:8080/

Второе: он отвечает только там и больше нигде:

sudo ss -tlnp | grep 8080

В столбце адреса должно быть указано 127.0.0.1:8080. Если там написано 0.0.0.0:8080 или *:8080, ваш onion-сайт доступен и из публичного интернета, что является первым пунктом в списке утечек. Строка listen 8080; без указания адреса означает привязку ко всем интерфейсам, что является настройкой по умолчанию.

Откройте адрес в Tor Browser. Первая загрузка занимает несколько секунд, пока клиент получает ваш дескриптор и строит цепочку соединения (rendezvous circuit).

Собственная документация The Tor Project рекомендует использовать unix-сокет вместо loopback-порта: HiddenServicePort 80 unix:/var/run/tor/onion_site.sock, где nginx прослушивает этот путь. К сокету невозможно обратиться с другого хоста, даже если позже на сервере появится второй сетевой интерфейс. Сложность заключается в правах доступа к файлам, так как nginx создает сокет, а tor подключается к нему от имени debian-tor, поэтому оба пользователя должны иметь доступ к директории. Использование loopback с проверкой вывода ss проще в настройке, и именно этот способ подразумевается в остальной части руководства.

При работе сайта через loopback серверу не требуются входящие правила для него. Оставьте открытым только 22 порт для себя и запретите всё остальное (стандартные настройки ufw для VPS). Помните, что межсетевой экран не отменяет работу сервиса, который привязан к 0.0.0.0, он лишь фильтрует пакеты, доходящие до него. Контейнеры делают эту ситуацию более критичной, так как публикация порта Docker создает правила iptables в обход ufw, поэтому -p 8080:80 выставляет ваш onion-бэкенд на публичный IP, даже если ufw сообщает, что порт закрыт. Публикуйте порты контейнеров как -p 127.0.0.1:8080:80.

Утечки, деанонимизирующие onion-сайт

Tor скрывает местоположение сервера. Tor не скрывает содержимое ответов сервера. Каждый пункт ниже — это данные, которые публикует ваш стек.

Сайт отвечает на публичном IP-адресе

Это самая частая ошибка. Сканеры непрерывно индексируют HTTP-ответы всех доступных IP-адресов, эти результаты публичны и доступны для поиска. Если вы отдаете одну и ту же страницу по публичному IP и через onion-адрес, их связь устанавливается одним запросом: одинаковый заголовок, хеш favicon, ETag, порядок заголовков. Строка listen 127.0.0.1:8080; выше — это решение. Проверьте это с другого компьютера, а не с самого сервера:

curl -sv --max-time 5 http://<your-public-ip>:8080/

Connection refused или таймаут — это правильный результат. Любой HTML означает, что сайт публичен. Если на сервере также работает сайт в обычном интернете (clearnet), выделите для него отдельный vhost и добавьте явный блок default_server в публичный слушатель, чтобы запрос с несовпадающим заголовком Host никогда не попадал в onion vhost.

Баннеры версий

curl -sI http://127.0.0.1:8080/ | grep -i '^server'

Стандартный nginx отвечает Server: nginx/1.24.0. Эта строка версии вместе с точным порядком других заголовков является отпечатком, который связывает ваш onion-адрес с обычным сайтом. server_tokens off; сокращает её до Server: nginx. Это не удаляет заголовок, а встроенной директивы для полного удаления в nginx нет, поэтому модуль headers-more — обычное решение, если вы хотите его убрать. PHP добавляет X-Powered-By, пока вы не установите expose_php = Off. etag off; относится к тому же списку, так как nginx формирует ETag на основе времени изменения и размера файла, поэтому одинаковые файлы, скопированные на два сервера, будут иметь одинаковый ETag на обоих.

Абсолютные URL, указывающие на ваш clearnet-домен

Тег rel="canonical", Open Graph og:url, RSS-лента, карта сайта, письмо для сброса пароля, жестко прописанный URL логотипа. Любой из них называет clearnet-сайт внутри страницы, отдаваемой через onion. Используйте относительные пути, такие как /static/logo.svg, и позвольте приложению считывать базовый URL из хоста запроса, а не из константы. Редиректы — это та же ошибка в другом месте: return 301 https://example.com$request_uri; в блоке catch-all отправляет посетителя onion-сайта на ваш реальный домен, а заголовок Location сразу выдает им ответ.

TLS-сертификат, общий с clearnet-сайтом

Onion-адрес аутентифицирует себя сам, так как адрес является открытым ключом, поэтому http:// через onion-соединение уже зашифровано из конца в конец, и Tor Browser считает его безопасным контекстом. Установка вашего существующего сертификата на onion vhost публикует связь между ними, так как каждый доверенный сертификат записывается в логи Certificate Transparency, а эти логи публичны, постоянны и доступны для поиска по имени. Оставьте сертификаты Let's Encrypt на clearnet vhost, а onion vhost оставьте на обычном HTTP.

Сторонние шрифты и аналитика

Шрифт из CDN (сеть доставки контента) или скрипт аналитики. Браузер посетителя загружает каждый из них напрямую, поэтому третья сторона узнает, что кто-то загрузил вашу страницу, и обычно — какую именно. Tor Browser со строгими настройками безопасности в любом случае заблокирует запрос, что приведет к поломке верстки. Размещайте все необходимые ресурсы на своем сервере.

Несовпадение заголовка Host

Если server_name не совпадает с заголовком Host, который отправляет tor, nginx переходит к серверу по умолчанию для этого адреса прослушивания. На сервере с одним vhost это незаметно, так как единственный блок server является и сервером по умолчанию. Добавьте clearnet vhost позже, и onion-запросы могут начать попадать на него, вместе с его каноническими тегами и редиректами. Повторяйте проверку curl -H 'Host: ...' после каждого изменения nginx и ищите в результате свой реальный домен:

curl -s -H 'Host: <your-address>.onion' http://127.0.0.1:8080/ | grep -o 'https\?://[^"]*' | sort -u

Понимание того, какой процесс владеет каким сокетом — это большая часть работы (как работают порты и слушающие сокеты в Linux).

Что остается в логах

Каждый запрос приходит с 127.0.0.1, поэтому nginx нечего записывать в качестве адреса посетителя, и access_log off; ничего вам не стоит. Приложение, работающее поверх него — другой вопрос, так как заказ, адрес электронной почты или метаданные загруженного файла — это то, с чем вам нужно работать. Ваши собственные привычки также имеют значение: администрирование сервера через незащищенный вход находится вне защиты Tor, поэтому рассматривайте защиту SSH на том же VPS как часть этой настройки.

Создайте резервную копию закрытого ключа, так как он является адресом

/var/lib/tor/onion_site/hs_ed25519_secret_key — это сервис. Здесь нет регистратора и механизмов восстановления. Если вы потеряете ключ, адрес будет утрачен безвозвратно. Скопируйте его, и любой, у кого окажется копия, сможет размещать собственный контент по вашему адресу; отозвать доступ к нему будет невозможно.

sudo systemctl stop tor@default
sudo tar -C /var/lib/tor -czf onion-keys.tgz onion_site
sudo chmod 600 onion-keys.tgz
sudo systemctl start tor@default

Зашифруйте этот архив (gpg -c onion-keys.tgz) и переместите его с сервера. Для восстановления на новом VPS потребуется этот архив и права доступа, ожидаемые процессом tor:

sudo systemctl stop tor@default
sudo tar -C /var/lib/tor -xzf onion-keys.tgz
sudo chown -R debian-tor:debian-tor /var/lib/tor/onion_site
sudo chmod 700 /var/lib/tor/onion_site
sudo systemctl start tor@default
sudo cat /var/lib/tor/onion_site/hostname

Тот же адрес появится на новом оборудовании через минуту или две после того, как tor повторно опубликует дескриптор. Это вся процедура миграции: не требуется ни изменение DNS, ни перевыпуск сертификатов.

Onion-Location, если сайт также доступен в обычном интернете

Если onion-адрес предназначен для удобства, а не для скрытности, анонсируйте его из vhost обычного сайта:

add_header Onion-Location http://<your-address>.onion$request_uri;

Tor Browser отобразит кнопку .onion available в адресной строке и предложит переключиться. Заголовок учитывается только в том случае, если страница в обычном интернете передается по HTTPS, а значение является корректным onion-URL.

Здесь есть нюанс с правилами nginx. Директивы add_header наследуются блоком location только в том случае, если в этом блоке нет собственных директив, поэтому location с собственным add_header молча отменяет Onion-Location. Повторите директиву в этом блоке или храните все заголовки ответов в одном месте. Публикация этого заголовка намеренно связывает два сайта, что правильно для зеркала, но недопустимо для ресурсов, которые должны оставаться не связанными.

Красивые адреса

mkp224o генерирует пары ключей до тех пор, пока один из них не создаст адрес, начинающийся с заданного вами префикса. Это поиск методом перебора, поэтому настраивать здесь нечего, кроме самого префикса и времени, которое вы готовы потратить на ожидание.

sudo apt install -y git gcc libc6-dev libsodium-dev make autoconf
git clone https://github.com/cathugger/mkp224o
cd mkp224o
./autogen.sh
./configure --enable-amd64-51-30k
make
./mkp224o -d onionkeys blog

Каждое совпадение сохраняется в onionkeys/<address>.onion/, содержащем hostname и hs_ed25519_secret_key. Установите его: остановите tor, скопируйте этот каталог поверх вашего HiddenServiceDir, а затем примените те же chown и chmod 700, что и при восстановлении выше.

Длина префикса определяет все затраты. Адрес представлен в формате base32, поэтому каждый дополнительный символ увеличивает ожидаемое количество ключей в 32 раза. Короткий префикс можно подобрать на ноутбуке. Длинный префикс не получится подобрать ни на одном имеющемся у вас устройстве. Кроме того, использование «красивого» префикса приучает пользователей обращать внимание только на первые символы, а не на весь адрес целиком — именно на этой привычке строятся фишинговые копии onion-сайтов.

Типовые сбои и соответствующие сообщения

После перезапуска отсутствует файл hostname. Tor не запустился или отказался использовать директорию. sudo journalctl -u tor@default -n 50 указывает на это:

/var/lib/tor/onion_site/ is not owned by this user (debian-tor, 108) but by root (0). Perhaps you are running Tor as the wrong user?

Так выглядит директория, созданная вручную. Исправьте владельца и права доступа или удалите директорию, чтобы Tor создал её самостоятельно.

Tor Browser показывает Onionsite Not Found (0xF0). Клиент не смог получить дескриптор, поэтому для сети по этому адресу ничего не опубликовано. Убедитесь, что Tor запущен и завершил процесс bootstrap, сверьте введённый адрес с sudo cat /var/lib/tor/onion_site/hostname посимвольно, а затем проверьте системное время. Tor требует точного времени для публикации и проверки дескрипторов, а timedatectl должен сообщать System clock synchronized: yes.

Адрес разрешается, но страница не загружается. Tor завершил процедуру rendezvous, но произошёл сбой на последнем этапе — при передаче трафика от Tor к Nginx. Этот этап является локальным, поэтому в логах Tor записей не будет. Выполните curl -sI http://127.0.0.1:8080/ на сервере. Connection refused означает, что Nginx не запущен или слушает адрес, отличный от того, на который указывает HiddenServicePort.

Страница загружается, но все ссылки ведут на ваш реальный домен. В шаблонах используются абсолютные URL. Выполните проверку grep -o 'https\?://[^"]*', описанную выше, и исправьте то, что она выведет, прежде чем публиковать адрес.

Всё работает, но перестаёт после перезагрузки. Перезагрузите сервер один раз намеренно, прежде чем полагаться на работоспособность сайта, а затем выполните sudo systemctl status tor@default и sudo systemctl status nginx. Сервис, запущенный вручную, выглядит так же, как и включённый в автозагрузку, до тех пор, пока машина не перезагрузится.

FAQ

Нужно ли открывать порт в брандмауэре для Tor onion-сервиса?

Нет. Процесс tor устанавливает только исходящие соединения: к серверам каталогов, точкам входа (introduction points) и узлам встречи (rendezvous relays). Входящие правила не требуются, а веб-сервер слушает только 127.0.0.1. Оставьте настройки ufw в состоянии default deny для входящего трафика, разрешив только SSH. Это свойство позволяет onion-сервису работать на машине за NAT (network address translation), даже если у неё нет публичного IP-адреса.

Почему я не могу открыть свой .onion-адрес в Tor Browser?

Проверяйте работоспособность от сервера к клиенту. sudo journalctl -u tor@default -n 50 должен показывать Bootstrapped 100% (done): Done, затем curl -sI http://127.0.0.1:8080/ на сервере должен возвращать строку состояния. Сверьте введённый адрес с содержимым файла hostname: один неверный символ делает адрес другим сервисом. Ошибка Onionsite Not Found (0xF0) означает, что дескриптор для адреса не найден; обычно это происходит, если tor не запущен или системное время установлено неверно.

Можно ли перенести onion-сайт на новый сервер, сохранив прежний адрес?

Да. Адрес вычисляется на основе hs_ed25519_secret_key, поэтому скопируйте всю папку HiddenServiceDir на новую машину, установите владельца debian-tor и права доступа 700, затем запустите tor. Адрес станет доступен сразу после повторной публикации дескриптора; обновлять DNS-записи не нужно. Если вы потеряете этот файл, адрес восстановить невозможно, поэтому создайте зашифрованную резервную копию вне сервера сразу после создания сервиса.

Нужен ли onion-сайту HTTPS-сертификат?

Нет. 56-символьный адрес является открытым ключом сервиса, поэтому соединение уже зашифровано и аутентифицировано на всём пути, а Tor Browser считает http:// на домене .onion безопасным контекстом. Использование вашего обычного сертификата для onion-хоста вредно: логи Certificate Transparency публичны и навсегда фиксируют связь между именами в одном сертификате. Единственная причина покупать сертификат для имени .onion — подтверждение бренда от центра сертификации, но эта связь будет публичной по определению.