SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-21

Как добавить заголовок Onion-Location в nginx

Настройте заголовок Onion-Location в nginx, чтобы Tor Browser предлагал переход на ваш onion-адрес. Узнайте, как избежать утечек через редиректы и сторонние ресурсы при переключении.

За что отвечает заголовок Onion-Location

Заголовок Onion-Location — это одна строка в конфигурации вашего виртуального хоста в открытой сети, которая сообщает Tor Browser адрес вашего onion-сервиса. Посетитель, который заходит на https://example.com через Tor, видит в адресной строке фиолетовую кнопку с надписью .onion available. Один клик перенаправляет пользователя на ваш onion-сервис. Это исключительно механизм обнаружения. Заголовок не создаёт onion-сервис и не скрывает никакой информации о вас.

Данное руководство предполагает, что обе части инфраструктуры уже готовы. У вас есть сайт на VPS под управлением nginx и работающий onion-сервис версии v3, настроенный на этот сайт. Если вторая часть ещё не готова, создайте её сначала: в руководстве размещение onion-сайта на VPS описаны параметры torrc и создание первого файла hostname. Далее рассматривается процесс объединения этих двух частей без утечки данных между ними.

Что требуется Tor Browser для обработки заголовка

The Tor Project указывает три условия. Все три должны выполняться, иначе кнопка не появится.

  • Значение Onion-Location должно быть корректным URL со схемой http: или https: и именем хоста .onion.
  • Веб-страница, задающая заголовок, должна передаваться по HTTPS.
  • Веб-страница, задающая заголовок, сама не должна быть onion-сайтом.

Второе условие — самое частое препятствие, а третье объясняет, почему не следует устанавливать этот заголовок на onion-хосте. Существует четвертое правило, которое отсутствует в документации, но реализовано в коде: Tor Browser обрабатывает заголовок только для документа верхнего уровня. Код сравнивает цель загрузки с документом перед выполнением любых действий, поэтому заголовок, полученный в ответе для таблицы стилей, изображения или API, игнорируется.

По умолчанию браузер отображает кнопку и ожидает клика. Пользователь, желающий автоматического перехода, может включить его в разделе Settings, затем Privacy and Security, затем Onion Services, где для параметра "Prioritize .onion sites when known" можно установить значение "Always". Вы не можете принудительно задать это поведение со стороны сервера. Рассматривайте заголовок как предложение, а не как редирект.

Добавление заголовка Onion-Location в nginx

Этот заголовок должен находиться в блоке server, который завершает TLS для вашего домена в открытой сети. Если поместить его в блок порта 80, ничего не произойдет, так как этот блок выполняет только перенаправление, а второе требование исключает использование заголовка на странице с обычным HTTP.

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

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

    root /srv/example.com/public;
}

$request_uri передает путь и строку запроса, поэтому пользователю на https://example.com/guides/tor будет предложен тот же путь в сети onion. Если это опустить, каждый посетитель будет попадать на главную страницу onion-ресурса вместо той, которую он просматривал.

always важен из-за задокументированного ограничения в nginx. add_header добавляет поле только в том случае, если код ответа равен 200, 201, 204, 206, 301, 302, 303, 304, 307 или 308. Ваша страница 404 является реальной точкой входа из результатов поиска, и без always она не будет содержать никакого заголовка.

Вторая ловушка nginx — это наследование, которое происходит без вывода предупреждений. Директивы add_header наследуются с предыдущего уровня конфигурации только в том случае, если на текущем уровне отсутствуют директивы add_header. Таким образом, блок location /assets/ { add_header Cache-Control ...; } отменяет действие Onion-Location уровня сервера для всех URL внутри него. Если вы устанавливаете заголовки для отдельных location, повторяйте строку Onion-Location внутри каждого из этих блоков. Как nginx выбирает блок server и location стоит прочитать, если такое поведение для вас в новинку.

Перезагрузите конфигурацию и проверьте как обычную страницу, так и несуществующую:

sudo nginx -t && sudo systemctl reload nginx
curl -sI https://example.com/ | grep -i onion-location
curl -sI https://example.com/no-such-page | grep -i onion-location

Обе команды должны вывести строку onion-location:. Вторая команда служит доказательством того, что always работает. Отсутствие вывода во втором случае означает, что флаг отсутствует или блок location перекрывает директиву.

HTML-тег meta, если вы не можете настроить заголовки

Статические хосты и некоторые панели управления CDN не позволяют добавлять произвольные заголовки ответа. То же самое значение работает в виде элемента meta в заголовке документа, так как браузер считывает его через те же данные заголовка документа, независимо от того, пришел ли он по HTTP или как тег http-equiv.

<meta http-equiv="onion-location" content="http://<your-onion-address>.onion" />

Три требования остаются в силе. Страница, содержащая тег, должна использовать HTTPS и не должна быть onion-ресурсом. Разница заключается в том, что тег содержит один фиксированный адрес без пути, так как нет серверной переменной для подстановки. Каждая страница, содержащая этот тег, предлагает одну и ту же onion-страницу. Это плата за использование резервного варианта, поэтому отдавайте предпочтение заголовку, если вы контролируете сервер.

Обслуживание onion-ресурса через отдельный vhost nginx

Сайт в открытой сети (clearnet) и onion-сервис не должны использовать один и тот же server block. Tor Browser отправляет Host: <your-onion-address>.onion. Если ни один server block не обрабатывает это имя, nginx переключается на default server, которым является ваш clearnet vhost, и каждый URL, генерируемый этим vhost, будет содержать ваш домен.

Настройте hidden service на порт, который слушает только интерфейс обратной связи (loopback):

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

Затем создайте для этого порта отдельный vhost:

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

    absolute_redirect off;
    port_in_redirect off;

    root /srv/example.com/public;
}

listen 127.0.0.1:8080 скрывает этот vhost от вашего публичного IP, чтобы сканирование адреса VPS не позволило получить содержимое и сравнить его побайтово с копией в открытой сети. absolute_redirect off заставляет nginx использовать относительные значения Location, поэтому редирект с завершающим слэшем для директории вернет Location: /guides/, а не полный URL. nginx и так формирует абсолютные редиректы на основе заголовка Host, а не server_name, так как server_name_in_redirect по умолчанию имеет значение off, но использование относительного редиректа полностью снимает этот вопрос.

Почему onion-страница всё ещё перенаправляет посетителей на сайт в clearnet?

Причина редко кроется в nginx. Проблема в вашем приложении. Любой механизм, формирующий абсолютный URL на основе настроенного адреса сайта, будет подставлять ваш домен независимо от того, какой vhost обработал запрос.

  • Тег rel="canonical", указывающий на https://example.com/.... Это наиболее частая причина: при просмотре исходного кода любой пользователь увидит точный адрес страницы в clearnet.
  • Редиректы, созданные средствами фреймворка, а не nginx, например, SECURE_SSL_REDIRECT в Django или параметры home и siteurl в WordPress.
  • og:url и другие метатеги для социальных сетей.
  • Записи в sitemap и RSS, которые по спецификации должны содержать абсолютные пути.
  • Страницы ошибок приложения, которые обычно содержат ссылку «вернуться на главную», сформированную на основе тех же настроек.

Решение зависит от вашего стека, универсального способа нет. Но есть универсальный метод проверки. Загрузите onion-страницу через Tor и выполните поиск вашего домена в ответе сервера.

curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ \
  | grep -i 'example\.com'

--socks5-hostname отправляет имя на SOCKS-порт Tor для разрешения, что необходимо, так как локально ваша система не может разрешить имя .onion. Порт 9050 является стандартным для установленного демона tor. Пустой результат означает отсутствие утечки. Любое совпадение указывает на страницу, которая передает ваш домен в clearnet каждому посетителю onion-ресурса. Выполните проверку для главной страницы, а затем для URL, который возвращает 404.

Проверьте цепочку редиректов отдельно, так как тело ответа при редиректе обычно пустое:

curl -sI --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/guides \
  | grep -i '^location'

Значение Location, указывающее на example.com, означает, что редирект перенаправляет посетителя onion-ресурса обратно в clearnet через выходной узел (exit node) в рамках запроса, который, как предполагал пользователь, оставался внутри сети Tor.

Не используйте сертификат для открытой сети в onion-сервисе

Адрес onion v3 вычисляется на основе открытого ключа самого сервиса, поэтому Tor выполняет аутентификацию и шифрование канала до конкретного сервиса еще до отправки HTTP-запроса. Использование обычного HTTP внутри onion-сервиса — это стандартная конфигурация, которая не эквивалентна передаче данных по обычному HTTP в открытой сети.

Если вы создаете vhost для onion-сервиса путем копирования конфигурации для открытой сети, вы переносите вместе с ней и ssl_certificate. В результате onion-сервис предъявляет сертификат, в списке альтернативных имен которого example.com. Возникают две проблемы. Браузер сообщает о несоответствии имени, так как URL является onion-адресом, а сертификат не охватывает его. Кроме того, каждый посетитель, который игнорирует предупреждение и переходит на сайт, получает подписанное подтверждение того, что эти два ресурса находятся на одном сервере. Храните vhost для onion-сервиса в отдельном файле с собственным server_name. Это также позволит избежать конфликтов с плагином Certbot для nginx, поскольку этот плагин вносит изменения в блок server, соответствующий домену, для которого вы запрашиваете сертификат.

Какой пакет tor выбрать и как обеспечить безопасность ключа службы

Пакет tor в архиве Ubuntu подходит для этой задачи и не требует дополнительной настройки. Он отстает от текущей стабильной версии, поэтому для службы, которая должна работать постоянно, используйте официальный репозиторий Tor Project и позвольте apt обновлять его вместе с остальными компонентами системы. По состоянию на август 2026 года процедура выглядит следующим образом:

sudo apt install apt-transport-https
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, заменив suite на кодовое имя вашего дистрибутива из lsb_release -c:

Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: noble
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpg
sudo apt update
sudo apt install tor deb.torproject.org-keyring

Пакет deb.torproject.org-keyring поддерживает актуальность ключа подписи, поэтому проверка репозитория не прекратится через год. Выберите один источник и придерживайтесь его. Пакет из архива дистрибутива и пакет из репозитория имеют разные версии, и при наличии обоих источников apt будет переключать вас между ними во время обновлений.

В HiddenServiceDir хранится идентификатор вашей службы. Файл hs_ed25519_secret_key в этом каталоге и есть ваш onion-адрес, так как адрес представляет собой открытую часть этой пары ключей. Если вы потеряете этот файл, адрес будет утрачен навсегда, так как не существует центрального органа, способного его восстановить. Если вы скопируете файл в небезопасное место, любой, кто получит к нему доступ, сможет запустить вашу onion-службу.

tor отказывается использовать каталог, доступный для чтения другим пользователям. Прежде всего проверьте права доступа и владельца:

sudo ls -ld /var/lib/tor/onion_site
sudo -u debian-tor cat /var/lib/tor/onion_site/hostname

В выводе должно быть указано drwx------, а владельцем и группой должны быть debian-tor в Debian и Ubuntu. Если права доступа шире, tor запишет в лог строку вида Permissions on directory /var/lib/tor/onion_site/ are too permissive., и служба не запустится. Исправьте это с помощью sudo chown -R debian-tor:debian-tor /var/lib/tor/onion_site, затем выполните sudo chmod 700 /var/lib/tor/onion_site, перезапустите службу командой sudo systemctl restart tor и проверьте результат через sudo journalctl -u tor@default -n 30.

Создавайте резервные копии этого каталога так же, как вы делаете это для закрытого ключа: храните их вне сервера и в зашифрованном виде. Никогда не добавляйте их в репозиторий, где хранится код вашего сайта. Если вам также нужен административный доступ к этому же серверу через Tor, подключение по SSH через onion-службу обеспечит более четкое разделение, чем открытие пути управления на публичном сайте.

Аналитика и сторонние ресурсы раскрывают больше, чем заголовок

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

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

Размещайте всё на своем домене. Размещайте шрифты локально. Откажитесь от сторонних тегов аналитики или перенесите их на свой сервер, где самостоятельно размещенная аналитика на VPS сохранит запрос внутри сети onion. Учитывайте, что настройки Tor Browser по умолчанию блокируют или ограничивают сбор данных большинством инструментов аналитики, что является правильным поведением. Если страница не может функционировать без стороннего скрипта, не публикуйте такую страницу в сети onion.

Составьте список того, что страница запрашивает на самом деле:

curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ \
  | grep -oE '(src|href)="https?://[^"]+"' | sort -u

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

Модель угроз в простом изложении

Onion-Location упрощает поиск onion-сервиса, и это единственная его функция. Он не обеспечивает анонимность для вас как для оператора, поскольку ваш домен в открытой сети (clearnet) по-прежнему связан с регистрационными данными, DNS-записями, сертификатом, опубликованным в логах Certificate Transparency, и аккаунтом VPS, к которому привязаны ваши платежные реквизиты. Он также не обеспечивает анонимность самого onion-адреса, так как вы только что опубликовали с этого домена явное и постоянное подтверждение того, что оба адреса принадлежат одному и тому же сайту. Преимущество получает пользователь: тот, кто пришел через Tor, может остаться внутри сети Tor, исключив из пути выходной узел и DNS-запросы для вашего домена. Если ваша цель — создать onion-сервис, к которому никто не сможет вас привязать, не публикуйте этот заголовок и не запускайте обе копии на одной машине.

Здесь возникают два связанных вопроса, и у каждого из них есть свой ответ. Разница между Tor и VPN определяет, что вы используете для собственного трафика, и это решение не зависит от того, что вы публикуете. А если пользователи в цензурируемой сети вообще не могут получить доступ к сайту в открытой сети, они никогда не увидят заголовок; в таких случаях мосты и подключаемые транспорты важнее всего остального, описанного на этой странице.

Проверка всей конфигурации

Выполните эти команды по порядку. Каждая из них должна вернуть ожидаемый результат.

  1. curl -sI https://example.com/ | grep -i onion-location выводит заголовок.
  2. Та же команда для URL, возвращающего 404, также выводит его.
  3. curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ возвращает вашу страницу.
  4. Поиск вашего домена в открытой сети (clearnet) через grep в этом выводе ничего не возвращает.
  5. Tor Browser на https://example.com отображает значок .onion available.

Если шаги с 1 по 4 выполнены успешно, а шаг 5 — нет, причина почти всегда кроется в источнике заголовка, а не в самом заголовке. Убедитесь, что браузер действительно загрузил HTTPS-страницу, а не кэшированный редирект, затем выполните curl -sI для того же URL, который вы открывали. Возможно, блок location для этого конкретного пути отбрасывает директиву серверного уровня.

FAQ

Почему Tor Browser не показывает кнопку «Доступен .onion»?

Сначала проверьте три документированных требования. Значение должно быть полным URL со схемой http: или https: и хостом .onion, поэтому «голый» адрес без схемы не сработает и не выведет ошибку. Страница должна отдаваться по HTTPS, поэтому заголовок, установленный в блоке редиректа с 80 порта, не будет прочитан. Кроме того, сама страница не должна быть onion-ресурсом. После этого проверьте Nginx: любая директива add_header внутри соответствующего блока location отменяет все add_header с уровня сервера, а без флага always заголовок будет отсутствовать в ответах 404 и 500. Выполните curl -sI для того же URL, который вы открывали в браузере, и убедитесь, что заголовок действительно передается по сети.

Нужен ли TLS-сертификат для моего onion-сайта?

Нет. Onion-адрес версии 3 вычисляется на основе открытого ключа сервиса, поэтому соединение аутентифицируется для конкретного сервиса и шифруется сквозным образом еще до отправки HTTP-запроса. Обычный HTTP внутри onion-сервиса — это стандартная конфигурация. Чего следует избегать, так это использования вашего clearnet-сертификата на onion-сайте. В поле Subject Alternative Names указан ваш домен, что вызывает предупреждение о несоответствии имени в браузере и подтверждает каждому посетителю, что оба сайта работают на одной машине.

Делает ли публикация Onion-Location мой сайт анонимным?

Нет. Заголовок — это публичное заявление вашего clearnet-домена о том, что конкретный onion-адрес принадлежит вам, и любой может его получить. Преимущество получает читатель, который может перейти на onion-версию и исключить выходной узел и DNS-запрос из своего пути. Как оператор вы не получаете анонимности и навсегда связываете два адреса. Onion-сервис, который не должен быть связан с вами, следует публиковать в другом месте, на оборудовании, которое не имеет ничего общего с clearnet-сайтом.

Можно ли использовать мета-тег вместо HTTP-заголовка?

Да, если вы не можете настроить заголовки ответа, что часто бывает на статическом хостинге. Разместите <meta http-equiv="onion-location" content="http://youraddress.onion" /> в заголовке документа. Применяются те же три требования: страница должна быть доступна по HTTPS и не должна быть onion-ресурсом. Единственное реальное отличие заключается в том, что тег содержит фиксированный адрес без пути, в то время как заголовок Nginx может добавлять $request_uri и предлагать посетителю ту же самую страницу на onion-сайте, а не просто главную.