Tunnel & Port Forwarding
What it is and why it matters
When your AI agent spins up a local development server — a React app on port 3000, a FastAPI service on port 8000, a database UI on port 5432 — that server is only reachable from your own machine. The tunnel feature solves this by establishing a secure public URL that proxies traffic to any local port.
You can share the URL with teammates, preview your app on a phone, or let a webhook service reach your local API. No manual port-forwarding or cloud deployment required.
OpenACP also runs an internal file viewer server. When an agent edits a file or produces a diff, the viewer generates a shareable link that renders the content with syntax highlighting (via Monaco editor) or side-by-side diff view.
Providers
OpenACP supports four tunnel providers. The active provider is configured once in ~/.openacp/config.json and applies to all tunnels.
Cloudflare (default, free)
Uses the cloudflared binary to create ephemeral *.trycloudflare.com URLs. No account required. OpenACP installs cloudflared automatically to ~/.openacp/bin/cloudflared if it is not already on your PATH.
Supports an optional custom domain if you have a Cloudflare account with a zone configured.
ngrok
Uses the ngrok binary. Requires ngrok to be installed separately (https://ngrok.com/download). Supports authtoken, domain, and region options.
bore
Uses the bore CLI to tunnel through bore.pub (or a self-hosted bore server). Requires bore to be installed (https://github.com/ekzhang/bore). Supports custom server, port, and secret options.
Tailscale Funnel
Uses tailscale funnel to expose a port over your Tailscale network. Requires Tailscale to be installed and authenticated (https://tailscale.com/download). The provider resolves your Tailscale hostname via tailscale status --json to construct the public URL.
Configuration
Add a tunnel block to ~/.openacp/config.json (see Configuration for the full tunnel config reference):
enabled
false
Enable or disable the tunnel feature
provider
"cloudflare"
One of cloudflare, ngrok, bore, tailscale
port
7080
Local port for the internal file viewer server. Auto-increments if in use.
maxUserTunnels
5
Maximum number of simultaneous user-created tunnels
storeTtlMinutes
60
How long file/diff viewer entries are kept in memory
auth.enabled
false
Require a bearer token to access the file viewer
options
{}
Provider-specific options (see below)
Provider-specific options
Cloudflare:
ngrok:
bore:
Tailscale:
CLI commands
Tunnels can be managed from the terminal:
Inside Telegram or Discord, if you have the agent integration installed, the agent can run these commands on your behalf — just ask it to "expose port 3000" or "give me a public URL for this Vite app."
File viewer
The file viewer is an internal HTTP server that OpenACP starts alongside the tunnel. When an agent reads, edits, or writes a file, it can register that file or diff in the viewer and send you a clickable link.
File view — renders file content with Monaco editor syntax highlighting. Supported languages include TypeScript, JavaScript, Python, Rust, Go, Java, Kotlin, Ruby, PHP, C/C++, C#, Swift, Bash, JSON, YAML, TOML, XML, HTML, CSS, SCSS, SQL, Markdown, Dockerfile, HCL, Vue, and Svelte.
Diff view — renders a side-by-side diff of old vs. new content.
The viewer enforces a 1 MB per-entry size limit and rejects file paths that fall outside the session's working directory (path traversal protection). Entries expire automatically after storeTtlMinutes (default 60 minutes).
Per-user tunnel limits
Each user or session can open up to maxUserTunnels tunnels simultaneously (default 5). This prevents runaway tunnel creation. Tunnels created by a session are tracked and can be stopped when the session ends via stopBySession.
Security
Auth token: When
auth.enabledis true, all requests to the file viewer require aBearer <token>header. Setauth.tokento a secret value.Path validation: The viewer validates every file path against the session's
workingDirectory. Files outside that directory are rejected.TTL: Viewer entries expire after
storeTtlMinutes. Expired entries are cleaned up every 5 minutes.Tunnel timeouts: If a provider process does not establish a tunnel within 30 seconds, it is killed and an error is returned.
Last updated
Was this helpful?
