tunnl.gg - Wystawianie lokalnych aplikacji w internet jedną komendą SSH
Pracujesz nad aplikacją na localhost:3000 i nagle potrzebujesz pokazać ją klientowi, przetestować webhooki od Stripe'a albo sprawdzić jak działa na telefonie kolegi. Co robisz? Deployujesz na staging? Konfigurujesz ngrok z tokenami i kontami? A może po prostu wpisujesz jedną komendę SSH i masz publiczny URL w 2 sekundy?
tunnl.gg to minimalistyczne narzędzie tunelujące oparte na SSH, które robi dokładnie jedną rzecz - i robi ją dobrze. Wystawia twoją lokalną aplikację w internet bez żadnej instalacji, bez zakładania konta, bez konfiguracji tokenów. Jedyne czego potrzebujesz to SSH, który i tak masz na swoim komputerze.
Czym jest tunnl.gg?
tunnl.gg to darmowa, open-source usługa tunelowania SSH napisana w Go. Pozwala wystawić dowolną aplikację działającą na localhost (lub w sieci lokalnej) pod publicznym adresem HTTPS z automatycznym certyfikatem SSL. Cały proces sprowadza się do jednej komendy:
ssh -t -R 80:localhost:8080 proxy.tunnl.ggPo wykonaniu tej komendy dostajesz losową subdomenę, np. https://crisp-cedar-c8b5a1d2.tunnl.gg, pod którą twoja lokalna aplikacja jest dostępna z całego świata.
Projekt został stworzony przez klipitkas i jest dostępny na GitHubie pod licencją MIT.
Dlaczego tunnl.gg?
Zero instalacji, zero konfiguracji
To największa zaleta tunnl.gg. Nie musisz:
- Instalować żadnego klienta ani CLI
- Zakładać konta
- Generować tokenów API
- Konfigurować czegokolwiek
SSH jest preinstalowany na praktycznie każdym systemie operacyjnym - macOS, Linux, a nawet Windows 10+ ma wbudowany klient SSH.
Porównanie z alternatywami
| Cecha | tunnl.gg | ngrok | localtunnel | Cloudflare Tunnel |
|---|---|---|---|---|
| Instalacja | Nie (SSH) | Tak (CLI) | Tak (npm) | Tak (CLI) |
| Konto | Nie | Tak | Nie | Tak |
| Darmowy plan | Tak (100%) | Ograniczony | Tak | Tak |
| HTTPS | Automatyczny | Automatyczny | Automatyczny | Automatyczny |
| Custom subdomena | Nie | Płatne | Opcjonalnie | Tak |
| WebSocket | Tak | Tak | Tak | Tak |
| Open source | Tak (MIT) | Nie | Tak | Klient (Apache 2.0) |
| Self-hosting | Tak | Nie | Tak | Nie |
Kiedy wybrać tunnl.gg?
tunnl.gg sprawdza się idealnie gdy:
- Potrzebujesz szybko pokazać coś klientowi lub współpracownikowi
- Testujesz webhooki (Stripe, GitHub, Slack)
- Debugujesz mobilną wersję aplikacji na fizycznym urządzeniu
- Pracujesz nad integracją OAuth i potrzebujesz publicznego callback URL
- Nie chcesz instalować kolejnego narzędzia w systemie
Jak korzystać z tunnl.gg?
Podstawowe użycie
Wystawienie lokalnego serwera na porcie 8080:
ssh -t -R 80:localhost:8080 proxy.tunnl.ggFlaga -t jest obowiązkowa - alokuje pseudo-terminal (TTY), dzięki czemu serwer może wyświetlić URL twojego tunelu. Po połączeniu zobaczysz:
Tunnel established!
https://crisp-cedar-c8b5a1d2.tunnl.ggWystawianie różnych portów
Jeśli twoja aplikacja działa na porcie 3000 (np. Next.js, React dev server):
ssh -t -R 80:localhost:3000 proxy.tunnl.ggAplikacja na porcie 5173 (Vite):
ssh -t -R 80:localhost:5173 proxy.tunnl.ggWystawianie zdalnego hosta
Możesz też wystawić aplikację działającą na innej maszynie w sieci lokalnej:
ssh -t -R 80:192.168.1.100:3000 proxy.tunnl.ggStabilne połączenie
Dla dłuższych sesji warto dodać keep-alive, żeby połączenie SSH nie zostało przerwane:
ssh -t -R 80:localhost:8080 -o ServerAliveInterval=60 proxy.tunnl.ggPomijanie strony ostrzegawczej
tunnl.gg wyświetla stronę ostrzegawczą (interstitial) przy pierwszym wejściu z przeglądarki - to ochrona przed phishingiem. Jeśli korzystasz z API lub curl, możesz ją pominąć:
curl -H "tunnl-skip-browser-warning: 1" https://subdomain.tunnl.ggArchitektura i działanie
tunnl.gg składa się z czterech głównych komponentów:
1. Serwer SSH (port 22)
Przyjmuje połączenia SSH z flagą -R (remote port forwarding). Nie wymaga autentykacji - to celowa decyzja projektowa dla darmowej usługi. Przy każdym połączeniu:
- Generuje zapamiętywalna subdomenę w formacie
przymiotnik-rzeczownik-hex(np.happy-tiger-a1b2c3d4) - Tworzy wewnętrzny listener TCP
- Rejestruje tunel w centralnym rejestrze
- Wysyła URL do klienta przez kanał SSH
2. Serwer HTTP (port 80)
Przekierowuje cały ruch na HTTPS odpowiedzią 301. Certyfikatów sam nie wystawia: trzeba je przygotować wcześniej, na przykład Certbotem, bo wbudowanej obsługi ACME w kodzie nie ma.
3. Serwer HTTPS (port 443)
Terminuje TLS i proxy'uje żądania z powrotem przez tunele SSH do lokalnych aplikacji użytkowników.
4. Endpoint statystyk (port 9090)
Dostępny tylko z localhost, udostępnia metryki: aktywne tunele, unikalne IP, łączne żądania, zablokowane adresy.
Przepływ żądania
Przeglądarka → HTTPS (tunnl.gg) → TLS termination → SSH tunnel → localhost:port- Przeglądarka wysyła żądanie do
https://happy-tiger-a1b2c3d4.tunnl.gg - Serwer HTTPS terminuje TLS
- Na podstawie subdomeny znajduje odpowiedni tunel SSH
- Proxy'uje żądanie przez połączenie SSH
- Żądanie dociera do twojej lokalnej aplikacji
- Odpowiedź wraca tą samą drogą
Limity i ograniczenia
tunnl.gg ma sensowne limity zabezpieczające przed nadużyciami:
| Limit | Wartość | Opis |
|---|---|---|
| Tunele na IP | 3 | Maksymalnie 3 jednoczesne tunele |
| Łącznie tuneli | 1000 | Limit globalny serwera |
| Żądania | 10/s (burst 20) | Rate limiting per tunel |
| Body żądania | 128 MB | Maksymalny rozmiar uploadu |
| Body odpowiedzi | 128 MB | Maksymalny rozmiar downloadu |
| WebSocket | 1 GB/kierunek | Limit danych per połączenie |
| Czas życia tunelu | 24h | Maksymalny czas trwania |
| Timeout bezczynności | 2h | Automatyczne zamknięcie przy braku ruchu |
| Połączenia/min na IP | 10 | Ochrona przed flood |
| Blokada IP | 1h | Kara za nadużycia |
Ograniczenia techniczne
- Obsługuje tylko ruch HTTP/HTTPS (brak TCP/UDP)
- Brak custom subdomen - zawsze losowe
- TLS jest terminowany po stronie serwera (serwer widzi ruch w postaci niezaszyfrowanej)
- Architektura single-server (brak skalowania)
- Brak autentykacji tuneli
Self-hosting
tunnl.gg jest w pełni open-source i można go postawić na własnym serwerze. To świetna opcja jeśli:
- Potrzebujesz kontroli nad danymi
- Chcesz własną domenę
- Potrzebujesz większych limitów
Wymagania
- Docker i Docker Compose
- Domena z rekordami DNS A (root i wildcard)
- Certyfikat SSL (Let's Encrypt)
Konfiguracja DNS
Dodaj dwa rekordy A wskazujące na IP twojego serwera:
tunnl.twojadomena.com → IP_SERWERA
*.tunnl.twojadomena.com → IP_SERWERACertyfikat SSL
Wygeneruj certyfikat wildcard za pomocą Certbot:
certbot certonly --manual --preferred-challenges dns \
-d "tunnl.twojadomena.com" \
-d "*.tunnl.twojadomena.com"Docker Compose
Gotowego obrazu w żadnym rejestrze nie ma, więc buduje się go z sklonowanego repozytorium:
services:
tunnl:
build: .
ports:
- "22:22"
- "80:80"
- "443:443"
environment:
- DOMAIN=tunnl.twojadomena.com
- TLS_CERT=/certs/fullchain.pem
- TLS_KEY=/certs/privkey.pem
volumes:
- ./data/certs:/certs:ro
- ./data/host_key:/host_key
restart: unless-stoppedZmienne środowiskowe
| Zmienna | Domyślna wartość | Opis |
|---|---|---|
| SSH_ADDR | :22 | Adres serwera SSH |
| HTTP_ADDR | :80 | Adres serwera HTTP |
| HTTPS_ADDR | :443 | Adres serwera HTTPS |
| STATS_ADDR | 127.0.0.1:9090 | Endpoint metryk |
| HOST_KEY_PATH | host_key | Ścieżka do klucza hosta SSH |
| TLS_CERT | /etc/letsencrypt/live/tunnl.gg/fullchain.pem | Ścieżka do certyfikatu TLS |
| TLS_KEY | /etc/letsencrypt/live/tunnl.gg/privkey.pem | Ścieżka do klucza prywatnego TLS |
| DOMAIN | tunnl.gg | Domena usługi |
Budowanie ze źródeł
Projekt wymaga Go 1.24+:
git clone https://github.com/klipitkas/tunnl.gg.git
cd tunnl.gg
make buildDostępne targety:
make build # Zoptymalizowana wersja
make build-small # Maksymalna optymalizacja rozmiaru (~6 MB)
make build-tiny # To samo plus pakowanie upx-em, jeśli upx jest zainstalowany
make build-dev # Szybka kompilacja z symbolami debugowania
make build-all # Linux i macOS, po dwie architektury (bez Windowsa)Bezpieczeństwo
Generowanie subdomen
tunnl.gg generuje subdomeny w formacie przymiotnik-rzeczownik-hex8, co daje ~4.4 biliona możliwych kombinacji (32 przymiotniki × 32 rzeczowniki × 4 miliardy wartości hex). Enumeracja jest niepraktyczna.
Ochrona przed phishingiem
Przy pierwszym wejściu z przeglądarki wyświetlana jest strona ostrzegawcza (interstitial), informująca że treść pochodzi z tunelu. Po zaakceptowaniu ustawiany jest cookie ważny 24 godziny.
Nagłówki bezpieczeństwa
Każda odpowiedź zawiera nagłówki:
X-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-origin
Na co uważać
- Brak autentykacji SSH oznacza, że każdy może utworzyć tunel
- TLS terminowany po stronie serwera - operator może teoretycznie widzieć ruch
- Nie używaj do przesyłania wrażliwych danych przez publiczną instancję
- Self-hosting rozwiązuje te problemy
Praktyczne scenariusze użycia
Testowanie webhooków
ssh -t -R 80:localhost:3000 proxy.tunnl.ggNastępnie w panelu Stripe podaj URL: https://twoja-subdomena.tunnl.gg/api/webhooks/stripe
Prezentacja dla klienta
Szybkie demo bez deployu:
ssh -t -R 80:localhost:3000 -o ServerAliveInterval=60 proxy.tunnl.ggWyślij URL klientowi - działa na każdym urządzeniu z przeglądarką.
Testowanie na urządzeniach mobilnych
Zamiast szukać IP w sieci lokalnej:
ssh -t -R 80:localhost:5173 proxy.tunnl.ggOtwórz URL na telefonie - HTTPS działa out of the box.
Dla telefonu podpiętego do tej samej sieci Wi-Fi to jest jednak rozwiązanie na wyrost, bo aplikacja idzie wtedy przez publiczny internet tylko po to, żeby wrócić do urządzenia stojącego obok. Portless załatwia ten sam problem bez wychodzenia poza sieć lokalną, podstawiając nazwany adres w miejsce szukania IP komputera. Tunel wygrywa dopiero wtedy, gdy telefon jest w innej sieci albo trzyma go ktoś inny.
Debugowanie integracji OAuth
Wiele providerów OAuth wymaga publicznego callback URL:
ssh -t -R 80:localhost:3000 proxy.tunnl.ggUstaw callback URL w konfiguracji providera na https://twoja-subdomena.tunnl.gg/auth/callback.
Czego tunel nie zastąpi
Warto nazwać granicę, bo tunel bywa używany do rzeczy, do których się nie nadaje, i kończy się to zawsze podobnie.
Tunel nie jest środowiskiem testowym. Działa dopóki Twój laptop jest włączony, podłączony do sieci i ma otwartą sesję, a maksymalnie dwadzieścia cztery godziny. Klient, który dostał odnośnik w piątek po południu i otworzył go w poniedziałek, zobaczy błąd. Do czegoś, co ma stać przez tydzień, potrzebujesz podglądu wdrożenia na Vercelu albo Railway, gdzie każda gałąź dostaje własny adres i nie zależy od Twojego sprzętu.
Tunel nie jest też sposobem na wystawienie usługi na stałe. Brak uwierzytelniania po stronie SSH oznacza, że każdy może utworzyć tunel na publicznej instancji, a losowa subdomena jest jedyną barierą przed dostępem do tego, co wystawiłeś. To ochrona przez nieodgadnięcie adresu, a nie kontrola dostępu. Jeśli za tunelem stoi panel administracyjny bez logowania, wystawiłeś go światu.
Trzecia granica dotyczy szyfrowania. Ruch jest zaszyfrowany między przeglądarką a serwerem usługi oraz między serwerem a Twoim komputerem, natomiast na serwerze pośrednim jest odszyfrowany. Operator publicznej instancji może technicznie zobaczyć jego treść. Do demonstracji to nie ma znaczenia, do danych osobowych klienta ma i wtedy właściwą odpowiedzią jest własna instancja albo tunel Cloudflare z uwierzytelnianiem.
Praktyczna reguła brzmi tak: tunel do tego, co trwa godziny i co możesz pokazać obcej osobie bez konsekwencji. Wszystko poza tym zasługuje na prawdziwe wdrożenie.
Kilka rzeczy, które oszczędzają czas
Nagłówek Host przychodzi z domeny tunelu, nie z Twojego localhosta. Część frameworków odrzuca takie żądania jako niedozwolone, więc jeśli widzisz błąd o nieprawidłowym nagłówku zamiast swojej aplikacji, dodaj domenę do listy dozwolonych hostów w konfiguracji serwera rozwojowego.
Odświeżanie modułów w locie działa przez ten sam tunel, ale klient próbuje łączyć się z adresem, który zna z konfiguracji budowania. Gdy podgląd na telefonie ładuje się raz i przestaje reagować na zmiany, to zwykle ten problem, a nie usterka tunelu.
Adresy bezwzględne w kodzie psują się natychmiast. Wszystko, co ma na sztywno wpisane http://localhost:3000, po drugiej stronie tunelu wskazuje na komputer odbiorcy. Ścieżki względne rozwiązują to bez żadnej konfiguracji.
Przy testowaniu webhooków pamiętaj, że po ponownym połączeniu dostajesz nową subdomenę i adres w panelu dostawcy przestaje być aktualny. Przy dłuższej pracy nad integracją to argument za własną instancją ze stałą domeną.
Warto też sprawdzić, jak Twoja aplikacja zachowuje się przy wolniejszym łączu. Ruch przechodzi przez serwer pośredni, więc opóźnienie jest zauważalnie większe niż przy wejściu na localhost, a to bywa jedyna okazja, żeby zobaczyć własny interfejs w warunkach zbliżonych do tego, co widzi użytkownik na telefonie w terenie.
FAQ
Czy tunnl.gg jest darmowe?
Tak, w 100%. Nie ma żadnych płatnych planów. Projekt jest open-source pod licencją MIT.
Czy potrzebuję konta?
Nie. Nie ma rejestracji, logowania, tokenów ani kluczy API.
Czy mogę wybrać swoją subdomenę?
Nie, subdomeny są generowane losowo. Jeśli potrzebujesz custom subdomen, rozważ ngrok lub self-hosting z modyfikacją kodu.
Jak długo działa tunel?
Maksymalnie 24 godziny. Po 2 godzinach bezczynności tunel jest zamykany automatycznie.
Czy obsługuje WebSocket?
Tak, z limitem 1 GB danych w każdym kierunku i 2-godzinnym timeoutem bezczynności.
Czy mogę go postawić na własnym serwerze?
Tak, tunnl.gg jest w pełni open-source. Instrukcje self-hostingu znajdziesz w repozytorium na GitHubie.
Czym się różni od ngrok?
ngrok to komercyjne narzędzie z bogatym zestawem funkcji (dashboard, replay, custom domeny). tunnl.gg to minimalistyczna, darmowa alternatywa - zero instalacji, zero kont, zero konfiguracji.
Kiedy sięgnąć po coś innego
Przy potrzebie stałej subdomeny, panelu z podglądem żądań i możliwością ich powtórzenia, ngrok daje więcej i przy intensywnej pracy nad integracjami ta różnica się broni. Przy usłudze, która ma stać na dłużej i mieć kontrolę dostępu, właściwym wyborem jest tunel od dostawcy sieci dostarczania treści. A przy czymś, co ma po prostu działać bez Twojego komputera, żaden tunel nie jest odpowiedzią, tylko wdrożenie.
Kod źródłowy i instrukcje samodzielnego uruchomienia stoją w repozytorium projektu, a opis architektury w osobnym dokumencie.