Expose a service#
Every instance publishes exactly one inbound port: SSH on 22. Anything else you start — a dashboard on 8080, vLLM on 8000, JupyterLab on 8888, a Gradio demo on 7860 — answers curl inside the instance and is a dead end from your laptop. Each method below fixes that the same way: a program inside the instance dials outward to Cloudflare or Tailscale, and they hand you a web address that forwards to your service. No inbound port is ever opened.
Outbound access is open, so all of this works without any change on our side. The examples use port 8080; substitute yours. Check the service answers inside the instance first:
curl -s http://localhost:8080 | head
If that prints nothing, fix the service before tunnelling — a tunnel forwards it exactly as it behaves inside the instance.
For copy-and-paste steps with a check after each one, follow the guide Expose a port over HTTP.
Warning
There is no port to open
Enverge does not open inbound ports on request, and there is no dashboard setting for it. An open port puts the service on the public internet, where anyone can find and probe it — including people who never got the address from you. The tunnels below stay scoped to the one service and audience you choose, and you can revoke them yourself at any time.
Just you: SSH port forwarding#
You already have what you need. Run this on your own machine, not in the instance, and leave the window open:
ssh -L 8080:localhost:8080 <user>@<instance-hostname>
Visit http://localhost:8080 in your browser. Closing the SSH window ends the access — no account, no public address, nothing installed to remove later. If you only check on a training run a few times a day, stop here.
A named group, all week: Cloudflare Tunnel with Access#
A stable address on your own domain, with a real check on who is let in. Needs a free Cloudflare account and a domain whose DNS Cloudflare manages. Do these in order (Cloudflare’s walkthrough):
Create the connection. In the Cloudflare dashboard, Networking → Tunnels → Create a tunnel. Paste the install command it gives you into the instance. That runs
cloudflaredas a background service dialling outward; nothing opens inward. Restrictive networks must allow outbound traffic on port 7844.Decide who may enter, before the address works. Under Zero Trust → Access controls → Applications, add a self-hosted application for the address you plan to use, such as
app.example.com, with an Allow policy naming your visitors’ emails or sign-in provider. This step comes first on purpose: a published address without it is open to anyone.Publish the service. Back in the tunnel, Add route → Published application — subdomain
app, your domain, service addresshttp://localhost:8080.
Verify from a private browser window: you should be asked to prove you are on the list before the service appears. Then try an account that is not on the list and confirm it is turned away. Widening or revoking access afterwards happens in the Access policy, without touching the instance. Off-switch: delete the published route, then reload the address and watch it fail — a route left in place keeps the address live.
Note
A new instance needs the tunnel installed again
The address and its Access policy live in your Cloudflare account, so they outlast any one instance. The cloudflared service does not: it is installed inside the instance, so launching a fresh one means running the install command again and pointing the route at it.
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. The --bg flag keeps Funnel running after you log out. Check it from a phone with Wi-Fi off, or any device outside your tailnet.
Note
Three things must be switched on first
Funnel needs MagicDNS and HTTPS certificates enabled for your tailnet, and this device given permission to use Funnel. The first run walks you through all three — those prompts are the setup, not an error.
Warning
Funnel has no sign-in of its own
Anyone with the address reaches your service directly, and the visitor’s identity is never passed to it. A Gradio demo with no password set becomes someone else’s free GPU. Give the service its own password, or use Cloudflare Access above, which checks names before requests reach the instance.
Funnel is still labelled beta, and its bandwidth limits are set by Tailscale and cannot be changed — a web interface fits inside them, serving large files to a crowd does not. The address must live under ts.net. Your instance is a container, and Tailscale normally wants a networking device that containers often lack: check with ls -l /dev/net/tun, and if it is missing, fall back to userspace networking (--tun=userspace-networking). For your own devices only, the private sibling tailscale serve --bg 8080 passes the visitor’s identity through to the service. Off-switch: tailscale funnel reset, then reload the address and watch it fail.
Choosing#
Your situation |
Use |
What you give up |
|---|---|---|
Only me, now and then |
SSH forwarding ( |
Ends when the SSH window closes |
Only my devices, always available |
Tailscale Serve |
Visitors must be on your tailnet |
Someone else, this afternoon |
Cloudflare Quick Tunnel |
Throwaway address, no streaming, and the link itself is the key unless you name emails |
A named group, all week |
Cloudflare Tunnel + Access |
Needs your domain on Cloudflare |
The public, no domain to offer |
Tailscale Funnel |
Beta, bandwidth limits, and your service must check who is calling |
Most people land on the first row. When the audience grows, move to the matching row rather than forwarding a temporary link again.
Note
Tunnel to localhost, in the same instance
An instance reaches the internet but not its neighbours: other instances, the host, and the host’s local network are blocked by design. Point the tunnel at a port on localhost inside the same instance.
For the longer walkthrough, with the reasoning behind each choice, see Expose a web app on an SSH-only instance.