RTX Pro 6000 is live, launch in one click→
All posts
9 min read

Your instance only gives you SSH. Here's how to put its web app on the internet.

SSHCloudflare TunnelTailscaleTunnelsGPU Instances

TL;DR: On an Enverge instance, SSH on port 22 is the only way in — a web app on 8080, 8000, 8888, or 7860 stays inside. Share it without opening a port: ssh -L for yourself, Cloudflare Quick Tunnel for someone else this afternoon, Cloudflare Tunnel with Access for a named group all week, or Tailscale Funnel when you have no domain. Whatever you choose, give the service its own password and use the off-switch when you are done.

In this post

Your training dashboard is running. Inside the instance, curl http://localhost:8080 answers at once. From your laptop at home, the same address is a dead end.

That is how the machine is set up. On an Enverge instance, SSH on port 22 is the only way in from the internet. Start anything else — a training dashboard on 8080, a vLLM server on 8000, JupyterLab on 8888, a Gradio demo on 7860 — and it stays inside the instance. There is no setting that opens it. Most rented GPU instances work the same way.

You can still share it. Each tool below does the same plain thing: a program inside the instance connects outward to Cloudflare or Tailscale, and that company hands you a web address that forwards to your service. No public port is ever opened on the instance.

So first ask who needs to reach this service:

  • Just you? SSH forwarding — skip the public internet.
  • Other people, today? A temporary Cloudflare link.
  • Other people, all week? A permanent address, with who is allowed decided before you share it.

The three routes, on one page:

Loading diagram…

Figure: three ways to reach a service inside an SSH-only instance — SSH forwarding for private access, Cloudflare Tunnel for a temporary or named public address, and Tailscale Serve or Funnel.

Everything below is one of those, in the order to consider them. We use port 8080 throughout; substitute yours. First, check inside the instance that the service works, and leave it bound to localhost if it offers the choice:

curl -s http://localhost:8080 | head

If that prints nothing, fix the service first. The tunnel forwards to it exactly as it behaves inside the instance.

If it is only you, do not go public

You already have what you need: the SSH connection you use every day. Run this on your laptop, not in the instance:

ssh -L 8080:localhost:8080 <user>@<instance-hostname>

Leave that window open and visit http://localhost:8080 in your browser. You are looking at the service inside the instance, carried through your SSH login.

Check it worked: stop the service inside the instance and reload; it should fail. Start it again; it should return. The reload tracks the instance service directly.

Day two: closing the SSH window closes the access — no account, no public address, nothing left behind. If you only check a training run a few times a day, stop here. (For the same privacy without reopening SSH, see Tailscale Serve below: tailscale serve --bg 8080.)

To share it this afternoon: Cloudflare Quick Tunnel

A collaborator needs to see the demo today. This is the fast path: no Cloudflare account, no domain. Install Cloudflare's small program, cloudflared, in the instance (downloads page):

sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install cloudflared

Then run:

cloudflared tunnel --url http://localhost:8080

It prints an address ending in trycloudflare.com. Send that address to your collaborator.

Check it worked: open the address on your phone with Wi-Fi off, or ask the collaborator. One look from outside beats testing on the same network.

Now the three things that go wrong, in the order people meet them:

  1. Anyone with the address gets in. A forwarded link is an open link. If you know who is coming, name them: cloudflared tunnel --url http://localhost:8080 --allowed-mail alice@example.com emails each listed visitor a one-time PIN first. It works in a browser, for people; scripts cannot type a PIN, so gate program-to-program calls differently.
  2. A page that loads but never answers. Quick Tunnels do not support Server-Sent Events, the streaming method many chat and generation interfaces use to show output as it arrives (Cloudflare's list). Test a real reply early; if it hangs, move to the permanent tunnel below.
  3. The address does not survive the day. Cloudflare allows 200 requests in flight at once, promises no uptime, and gives you a new address every run. Fine for an afternoon; frustrating by Thursday.

Off-switch: Ctrl+C. Closing that terminal also ends the link, so keep the window open for the length of the demo.

To keep it up all week: Cloudflare Tunnel with Access

Remember the collaborator from this afternoon? By Thursday she needs the link again, and two other people have been forwarded the thread. That is the moment for a permanent Cloudflare Tunnel: an address you can put in a document and hand to a named group. It costs a free Cloudflare account and a domain whose DNS Cloudflare manages; you get a stable address on your own domain, running without a window held open — and a real check of who is let in.

In this order (Cloudflare's walkthrough):

  1. Create the connection. Dashboard: Networking → Tunnels → Create a tunnel. Name it after the service, then paste the install command it shows you into the instance. That installs cloudflared as a background service connecting outward; nothing opens inward. (Restrictive networks must allow outbound to Cloudflare on port 7844.)
  2. Decide who may enter — before the address works. In Zero Trust → Access controls → Applications, add a self-hosted application for your planned address, such as app.example.com, with an Allow policy naming visitors' emails or sign-in provider. Nobody passes unless they match. This precedes step 3 on purpose: Cloudflare warns a published address without this check is open to anyone.
  3. Publish the service. Back in the tunnel: Add route → Published application — subdomain app, your domain, service address http://localhost:8080.

Check it worked: from a private browser window, open the address. You should be asked to prove you are on the list before the service appears. Then try an address or account that is not on the list; it should be turned away. Only then share it.

Day two: the background service is meant to return when the instance restarts, and the address stays the same. Widening or revoking the list happens in the Access policy, without touching the instance. Off-switch: delete the published route, then reload the address to confirm it fails. A route left in place keeps the address live.

No domain? Tailscale Funnel

Tailscale is a private network of your own devices; Funnel lets the whole internet reach one service on one device, at an address on Tailscale's domain. In the instance:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale funnel --bg 8080

The last command prints an address like https://<machine>.<tailnet>.ts.net. (Your tailnet is simply your set of devices in Tailscale; ts.net is its naming scheme.) The --bg flag keeps Funnel running in the background after you log out, and by Tailscale's documentation it picks up again after a restart. The first run talks you through its requirements: MagicDNS and HTTPS certificates switched on, and permission for this device to use Funnel.

Check it worked: open the address on a phone with Wi-Fi off. Use a device outside your tailnet for this check.

Costs and limits. Funnel is still labelled beta. Its traffic has bandwidth limits Tailscale sets and does not let you change; a web interface fits those limits, large files for a crowd do not. The address must live under ts.net. Funnel has no sign-in of its own. Put a Gradio demo on it with no password set, and anyone with the address can run generations on your GPU. Visitor identity is not passed to the service. Give the service its own password, or use Cloudflare above, where Access checks names before requests reach the instance. Serve, the private sibling — tailscale serve --bg 8080 — reaches only your own devices and passes the visitor's identity to the service.

One caution about the machine you are renting. It is a container, and Tailscale normally needs a networking device, /dev/net/tun, that rented containers often do not include. Look first: ls -l /dev/net/tun. If it is missing and tailscale up complains, Tailscale documents a fallback, userspace networking (--tun=userspace-networking). This step varies most between rented machines.

Off-switch: tailscale funnel reset. Run it, then reload the address and watch it fail.

Before you paste that address anywhere

Whichever method you chose, take two minutes here. A tunnel expands the audience for your service. The service keeps the permissions it already gives each visitor. A JupyterLab with its token switched off, a Gradio app with no password set, a vLLM endpoint with no API key — each is one forwarded link away from being someone else's free GPU.

  • Set the service's own password anyway. Links get forwarded; its own sign-in is the layer that still works then.
  • Leave the service on localhost so the tunnel is the only way in.
  • Treat an ungated address as a password. Keep it out of public posts and shared documents.
  • Mind what a public service spends. A stranger with the address can set your GPU working — capacity is finite, as our serving benchmark on one RTX Pro 6000 shows. Gate it first.
  • Use the off-switch today. Quick, Ctrl+C; Cloudflare, delete the route; Funnel, tailscale funnel reset. Then watch the address fail.

Choosing, in one table

Your situationUseWhat you give up
Only me, now and thenSSH forwarding (ssh -L)Ends when the SSH window closes
Only my devices, always availableTailscale ServeVisitors must be on your tailnet
Someone else, this afternoonCloudflare Quick TunnelA throwaway address; no streaming replies; the link itself is the key unless you name emails
A named group, all weekCloudflare Tunnel + AccessNeeds your domain on Cloudflare
The public, no domain to offerTailscale FunnelBeta, bandwidth limits, and your service must check who is calling

Start with your situation in the left column. Most people land on the first row. SSH forwarding ends with the session and leaves nothing installed to remove later.

When the audience grows, move to the matching row. After a temporary link has been forwarded a couple of times, replace it with a permanent setup matched to the new audience.

Frequently asked questions

Can support just open port 8080 for me? On Enverge, no. Opening that port would place the service on the open internet. Anyone could find it and probe it, including people who never received the address from you. Consider what tends to be listening on rented GPU instances: JupyterLab, dashboards, and small APIs. Several ship with sign-in switched off or optional. File access may sit a click away. A stranger could also submit work to the GPU. Some clouds will open a port on request; the exposure starts with the port opening and ends when you remember to close it. Under Enverge's SSH-only default, every service you start stays inside the instance, this week's debug tool included. You can revoke the tunnels described above yourself, at any time, for the one service and audience you picked.

My page loads through the link but never replies. Why? On a Quick Tunnel, suspect streaming: it cannot carry the live, piece-by-piece replies many AI interfaces use, so the page can load while the reply stalls. Try a permanent Cloudflare Tunnel or Funnel. If the service responds through Funnel and runs slowly, check Funnel's bandwidth limits.

Does the tunnel hide my machine? Visitors connect to Cloudflare's or Tailscale's address, so the instance's location stays private. The service itself is fully visible to anyone who reaches it. Give it its own password for that reason.

Do I need my own domain? Only for the permanent Cloudflare address. Quick uses trycloudflare.com, Funnel ts.net, and the private options need no public name.