Sabuj Kundu 26th Dec 2025

Modern development lives in an awkward space: your app runs locally, but the outside world needs access. Webhooks, mobile testing, third-party callbacks, and client demos all demand a public URL. This is exactly where Tunnelto shines.


What Is Tunnelto?

Tunnelto is an open-source tunneling tool that exposes your local development server to the internet through a secure tunnel. Think of it as a developer-friendly alternative to services like ngrok, but with one crucial difference: you can self-host it.

At a high level, Tunnelto works like this:

  • You run a Tunnelto server on a public machine (VPS or cloud server).
  • You run a Tunnelto client on your local machine.
  • The client opens a secure tunnel to the server.
  • External requests hit the server and are forwarded to your local app.

This makes Tunnelto ideal for:

  • Webhook testing (Stripe, PayPal, GitHub, etc.)
  • Local WordPress, Laravel, or Node.js development
  • Client previews without deploying code
  • Teams that want control over infrastructure

Why Self-Host Tunnelto?

Self-hosting is not about distrust; it is about control.

  • No usage limits
  • No vendor lock-in
  • Custom domains and subdomains
  • Your data never leaves your infrastructure

If you already manage servers, self-hosting Tunnelto is surprisingly lightweight.


Prerequisites

Before starting, make sure you have:

  • An Ubuntu 20.04+ VPS
  • A domain name (example: example.com)
  • A subdomain pointing to your server (example: tunnel.example.com)
  • Root or sudo access
  • Nginx installed

Step 1: Install Tunnelto Server on Ubuntu

Tunnelto is distributed as a single binary.


# Download Tunnelto server
curl -L https://github.com/agrinman/tunnelto/releases/latest/download/tunnelto-linux-amd64 \
-o tunnelto

# Make it executable
chmod +x tunnelto

# Move to a global path
sudo mv tunnelto /usr/local/bin/tunnelto

Verify installation:


tunnelto --help

Step 2: Run Tunnelto Server

Start the server on a private port (example: 3000):


tunnelto server --port 3000

For production, you should run this via systemd or a process manager like pm2.


Step 3: Configure Nginx as a Reverse Proxy

Create a new Nginx config file:


sudo nano /etc/nginx/sites-available/tunnelto

Add the following configuration:


server {
    listen 80;
    server_name tunnel.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Enable the site:


sudo ln -s /etc/nginx/sites-available/tunnelto /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 4: Enable HTTPS with Let’s Encrypt

Secure tunnels deserve secure transport.


sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d tunnel.example.com

Once complete, your Tunnelto server will be available at:

https://tunnel.example.com


Step 5: Install Tunnelto Client (Local Machine)

Linux


curl -L https://github.com/agrinman/tunnelto/releases/latest/download/tunnelto-linux-amd64 \
-o tunnelto
chmod +x tunnelto
sudo mv tunnelto /usr/local/bin/tunnelto

macOS


brew install tunnelto

Windows (PowerShell)


winget install tunnelto

Step 6: Expose Your Local App

Assume your local app runs on port 8000.


tunnelto --host https://tunnel.example.com http://localhost:8000

Tunnelto will output a public URL pointing to your local server. Any request to that URL is forwarded directly to your machine.


Security Notes

  • Use HTTPS only in production
  • Restrict access using firewall rules if possible
  • Rotate domains or tokens for sensitive testing

A tunnel is a doorway. Treat it like one.


Final Thoughts

Tunnelto sits at a sweet intersection of simplicity and power. It does one thing—expose local services—and does it cleanly. By self-hosting, you gain reliability, privacy, and freedom without adding much complexity.

For developers working with APIs, webhooks, WordPress plugins, Laravel apps, or SaaS integrations, a self-hosted Tunnelto setup becomes a quiet but indispensable tool in the workflow.


Adding Authentication to Tunnelto

A public tunnel without authentication is like leaving your dev server unlocked. Tunnelto supports authentication tokens that allow only trusted clients to connect. This is especially important when your Tunnelto server is exposed via a real domain and HTTPS.

Generate an Authentication Token

On your Tunnelto server, generate a strong token:


openssl rand -hex 32

Example output:


9c4f1c2d3b0a7f91e8d2c5a4c93a8f1cbbd3e7f6e9c1b8a5d2e4f7a1b9d

Run Tunnelto Server with Authentication

Restart the Tunnelto server with the token enabled:


tunnelto server \
  --port 3000 \
  --auth-token 9c4f1c2d3b0a7f91e8d2c5a4c93a8f1cbbd3e7f6e9c1b8a5d2e4f7a1b9d

Only clients that present this token will be allowed to establish tunnels.

Connect from Client with Authentication

On the developer machine:


tunnelto \
  --host https://tunnel.example.com \
  --auth-token 9c4f1c2d3b0a7f91e8d2c5a4c93a8f1cbbd3e7f6e9c1b8a5d2e4f7a1b9d \
  http://localhost:8000

If the token is missing or invalid, the connection is rejected immediately. This keeps random scanners and curious bots out of your tunnels.


Custom Subdomains per Developer

One of the quiet superpowers of self-hosted Tunnelto is predictable URLs. Instead of random subdomains, each developer can have their own permanent subdomain.

Example structure:

  • sabuj.tunnel.example.com
  • alice.tunnel.example.com
  • bob.tunnel.example.com

This is extremely useful for:

  • Team-based development
  • Persistent webhook URLs
  • Client demos that should not break

DNS Configuration

Create a wildcard DNS record:


Type: A
Host: *.tunnel
Value: YOUR_SERVER_IP

This allows any subdomain under tunnel.example.com to resolve to your server.

Nginx Wildcard Server Configuration

Update your Nginx server block:


server {
    listen 80;
    server_name *.tunnel.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

Reissue HTTPS certificates with wildcard support (requires DNS validation):


sudo certbot certonly \
  --dns-cloudflare \
  -d "*.tunnel.example.com"

Developer-Specific Tunnel

Each developer connects using their assigned subdomain:


tunnelto \
  --host https://sabuj.tunnel.example.com \
  --auth-token DEVELOPER_TOKEN \
  http://localhost:8000

Tunnelto automatically maps incoming requests for that subdomain to the correct tunnel.
No collisions. No confusion.


Operational Best Practices

  • Use a unique auth token per developer
  • Rotate tokens periodically
  • Restrict Tunnelto server ports using a firewall
  • Run Tunnelto server as a systemd service

At this point, Tunnelto stops being a simple tunnel and starts behaving like infrastructure.
Lightweight, quiet infrastructure—but infrastructure nonetheless.

Need to build a Website or Application?

Since 2011, Codeboxr has been transforming client visions into powerful, user-friendly web experiences. We specialize in building bespoke web applications that drive growth and engagement.

Our deep expertise in modern technologies like Laravel and Flutter allows us to create robust, scalable solutions from the ground up. As WordPress veterans, we also excel at crafting high-performance websites and developing advanced custom plugins that extend functionality perfectly to your needs.

Let’s build the advanced web solution your business demands.