HTTP-тунель для локального сайту зібрали на OpenSSH і Nginx

Вінсент Берна показав, як відкрити доступ до локального вебсервісу через власний сервер. У цій схемі OpenSSH створює тунель, а Nginx приймає HTTPS-запити й перевіряє доступ.

· 4 хв читання · 4 коментарі

5 жовтня 2026 року Вінсент Берна описав спосіб відкрити локальний вебсервіс через власний сервер без окремого тунельного клієнта. Як пише автор у матеріалі Самостійно розгорнуті HTTP-тунелі з SSH і Nginx, для цього він використовує OpenSSH і Nginx: SSH з’єднує віддалений порт із локальним сервісом, а Nginx приймає HTTPS-запити й спрямовує їх у тунель. Завдання з матеріалу — дати іншій людині подивитися чернетку блогу, яка поки доступна лише на localhost:8080.

Як запит потрапляє на локальний порт

Розробник запускає зворотне перенаправлення SSH з віддаленого сервера до локального сервісу. У команді ssh -N -R 0:localhost:8080 web02.luffy.cx нуль означає, що вільний віддалений порт вибере сервер. У прикладі з матеріалу він виділив порт 41535. Поки SSH-з’єднання відкрите, запити до цього порту можна передавати сервісу на машині розробника.

На віддаленому сервері Nginx приймає HTTPS-запити до піддоменів на кшталт p41535.ssh.luffy.cx. Номер порту він бере з імені хоста й проксіює запит на 127.0.0.1:41535. Для таких адрес автор налаштовує DNS-запис із підстановним іменем і сертифікат Let’s Encrypt для групи піддоменів. Перевірка для видачі сертифіката відбувається через DNS-01; у його випадку NixOS отримує сертифікати автоматично.

Схема не прив’язана до одного заздалегідь призначеного порту: під час наступного підключення SSH може виділити інший, а правило Nginx візьме нове число з адреси. Зворотний бік — одного Nginx недостатньо. Потрібні сервер з OpenSSH, налаштовані DNS і HTTPS, а також відкрите SSH-з’єднання з машиною, на якій працює локальний сервіс. Це спосіб використати наявну інфраструктуру, а не уникнути її налаштування.

Посилання з перевіркою доступу

У базовій конфігурації номер порту залишається єдиною перешкодою для доступу до сторінки: якщо його дізнатися, запит пройде через проксі. Берна додає перевірку через модуль Nginx ngx_http_secure_link_module. Посилання містить хеш і час закінчення дії, записані як ім’я користувача перед доменом. Клієнт передає цю частину адреси засобами HTTP Basic, а Nginx порівнює отриманий хеш із хешем, обчисленим за строком дії, номером порту й серверним секретом.

Якщо хеш неправильний або його немає, сервер відповідає кодом 401 і запитує облікові дані; після закінчення строку дії посилання повертає 410. У прикладі автора строк дії становить 86400 секунд. Перед передаванням запиту локальному сервісу Nginx видаляє заголовок Authorization, у якому надійшли дані для перевірки. Конфігурація також передбачає проксіювання WebSocket-з’єднань.

Створювати таку адресу вручну незручно: спочатку потрібно дізнатися виділений SSH-порт, потім обчислити хеш і сформувати посилання. Тому автор написав допоміжний скрипт для сервера. Він знаходить процеси SSH-сеансу, визначає пов’язані з ними порти, що прослуховуються, виводить адреси й утримує сеанс відкритим. Для пошуку портів скрипт запускає ss через sudo -n — якщо відтворювати цю схему, такий доступ доведеться налаштувати. Запис у конфігурації SSH дає змогу викликати скрипт під час підключення.

Що це дає під час роботи із сайтом

Підтверджений матеріалом сценарій — показати людині чернетку сторінки, що працює на локальній машині. Одержувач відкриває видану HTTPS-адресу; запит надходить на сервер із Nginx і через зворотне перенаправлення SSH потрапляє до локального сервісу. Окремо розміщувати чернетку на віддаленому вебсервері в цьому сценарії не потрібно, але тунель працює, поки відкритий SSH-сеанс.

У посиланні містяться дані для доступу. Якщо переслати його ще комусь, новий одержувач теж зможе відкрити сторінку до закінчення строку дії посилання. Строк обмежує доступ у часі, але сам по собі не обмежує коло людей, до яких потрапила адреса.

Моя думка: менше залежностей, більше власної відповідальності

Мені подобається, що тут можна простежити шлях запиту й призначення кожного елемента. SSH відповідає за перенаправлення, Nginx — за HTTPS і перевірку посилання. Якщо обидва вже працюють на сервері, спеціалізований тунельний клієнт не потрібен. Але я б не називав налаштування простим лише тому, що команда підключення коротка: DNS, сертифікат, правила Nginx і доступ скрипта до відомостей про порти залишаються частиною рішення.

Перш ніж радити такий варіант команді, я б запитав, як часто їй потрібні тимчасові прев’ю та хто підтримуватиме серверну конфігурацію. Для поодинокого перегляду чернетки користь для мене неочевидна, якщо все доводиться налаштовувати з нуля. За регулярної роботи я б заздалегідь домовився про строк дії посилань і про те, кому їх пересилають. Інакше зручна команда приховує довгий перелік припущень, який дасться взнаки вже під час використання.

Джерела

Звідки новина. Текст — переказ своїми словами, факти — з джерела, думка — автора.

  1. Self-hosted HTTP tunnels with SSH and Nginx vincent.bernat.ch

Про автора

Петеріс Залітіс

фронтенд-розробник e-commerce

Підтримую магазини з великими каталогами й регулярно розгрібаю наслідки «швидкого» встановлення плагінів. Перш ніж прийняти пораду про новий стек, запитую, що саме він поліпшить і як це виміряти.

Усі публікації автора

Бекенд 4 хв читання

Злам інфраструктури зон .gh, .sl і .as дав змогу випустити TLS-сертифікати для чужих доменів

Злам інфраструктури доменних зон .gh, .sl і .as дав зловмисникам змогу змінити DNS-записи й отримати чужі HTTPS-сертифікати, зокрема для доменів Google. Компанія заблокувала їх у Chrome і радить власникам сайтів перевірити журнали CT.

Бекенд 3 хв читання

Next.js випустив оновлення безпеки для гілок 15.5 і 16.3

Next.js випустив версії 16.3.8 і 15.5.27, що усувають уразливості кешування, розкриття даних та оптимізації зображень. Командам рекомендують оновити застосунки й перевірити функції, які вони використовують.

Фронтенд 3 хв читання

Bez генерує браузерний рушій за вебспецифікаціями й тестами

Bez створює браузерний рушій за вебспецифікаціями, звіряючи результат із Chromium, Firefox і WebKit. Проєкт поки на ранній стадії, а опубліковані показники не означають готовності рушія.

Написати коментар

Не публікується. Надішлемо посилання, щоб підтвердити коментар.

Без посилань і реклами. Перший коментар публікується після перевірки. Надсилаючи коментар, ви погоджуєтеся з політикою конфіденційності.

  1. Цікаво, чи можна в цій схемі обмежити доступ не лише паролем або токеном у Nginx, а й конкретними IP? Для чернетки на localhost:8080 це додало б ще один простий рівень захисту.

    1. Петеріс Залітіс Автор публікації

      Так, можна: на рівні Nginx для потрібного location задають allow для довірених IP і deny all, а перевірку токена залишають другим бар’єром. Але якщо перед Nginx є проксі, треба коректно налаштувати real_ip, інакше фільтр бачитиме адресу проксі, а не відвідувача. Тут важливо уточнити критерій: доступ має бути лише з офісної мережі чи також із домашніх динамічних IP?

    2. @natalia_matos можна обмежити IP у Nginx через allow/deny, наприклад дозволити лише адресу людини, якій показуєш чернетку, а решту відхиляти. Але якщо в неї змінна адреса чи вона за NAT, такий «простий рівень» швидко перетвориться на переписку про доступ; токен у Nginx зазвичай практичніший, а IP-фільтр — додатковий бар’єр, не заміна автентифікації.

      1. @femke.u, уточню: у цій схемі Nginx бачить IP того, хто під’єднався до нього, тож за проксі чи CDN allow/deny може вимагати окремо налаштувати реальну адресу клієнта; інакше фільтр перевірятиме адресу проксі.