Automatic Port Forwarding for Docker Containers
Use a single exposed port to quickly access services running on your container.
Automatic port detection, port forwarding, and app aliasing. CLI, Browser UI, and HTTP API.
conduit watches local listening TCP ports and forwards HTTP requests by path:
- Incoming:
http://<host>:<public_port>/<internal_port>/<path...> - Forwarded to:
http://127.0.0.1:<internal_port>/<path...>
Example:
http://myserver.com:9000/3000/api/users->http://127.0.0.1:3000/api/users
Why Conduit
-
Auto Discovery: Polls for local listening ports to find running services.
-
Single-Port: Expose one port (e.g.
9000) and reach all your apps through it. -
Consistent: Deployment platforms vary in their port forwarding strategy. Conduit keeps it consistent.
-
App Aliases: Map ports to friendly names so URLs are easy to remember across restarts.
-
Simple UI: Use CLI or a browser UI to manage your apps.
-
Built-in API: Use the HTTP API for automation / workflows.
Route Modes
Port route
- Incoming:
http://<host>:<public_port>/<internal_port>/<path...> - Forwarded to:
http://127.0.0.1:<internal_port>/<path...>
Example:
http://myserver.com:9000/3000/api/users->http://127.0.0.1:3000/api/users
Named route
Define a mapping in settings:
{
"apps": {
"myapp1": 3000,
"myapp2": 5173
}
}Then:
http://myserver.com:9000/myapp1/api/users->http://127.0.0.1:3000/api/usershttp://myserver.com:9000/myapp2/->http://127.0.0.1:5173/
Conduit only proxies if the target port is currently listening.
Install
- Install Go (1.22+).
- Build:
Run
./conduit -public-host 0.0.0.0 -public-port 9000
With one open/public port, examples look like:
http://<host>:9000/3000/for direct port routinghttp://<host>:9000/api/for alias routing
Useful flags:
-public-hostbind host (default0.0.0.0)-public-portbind port (default9000)-target-hostupstream host (default127.0.0.1)-poll-intervalrescan interval (default2s)-settings-filesettings path (default~/.conduit/settings.json)-no-httprun without starting the HTTP server-no-uialias for-no-http-jsonJSON output for CLI commands
Terminal Interface
Conduit supports CLI commands against the same state used by HTTP endpoints:
conduit ports
conduit apps list
conduit apps set api 3000
conduit apps delete api
conduit healthUse -json for machine-readable output:
conduit -json apps list conduit -json ports
Settings File
Default location:
~/.conduit/settings.json
Format:
{
"apps": {
"api": 3000,
"web": 5173
}
}Rules:
- Names are normalized to lowercase.
- Allowed characters:
a-z,0-9,.,_,- - Max name length: 63 chars.
- Port must be
1-65535.
Dashboard UI
Open:
http://<host>:<public_port>/ui
The dashboard shows:
- Current name-to-port mappings
- Which mapped ports are running
- Running ports that do not yet have names
- Quick links for named route and numeric route
- Add/update/remove mapping form
API
GET /health
Health check.
Response:
GET /ports
Returns currently discovered listening local ports.
Response example:
{
"ports": [22, 3000, 5432],
"count": 3,
"updated_at": "2026-02-27T03:45:00Z"
}GET /apps
Returns configured app mappings plus running state and quick route paths.
Response example:
{
"apps": [
{
"name": "api",
"port": 3000,
"running": true,
"named_path": "/api/",
"port_path": "/3000/",
"named_url": "http://localhost:9000/api/",
"port_url": "http://localhost:9000/3000/"
}
],
"unmapped_running_ports": [5432],
"settings_file": "/home/node/.conduit/settings.json",
"updated_at": "2026-02-27T03:45:00Z"
}POST /apps
Create/update/delete app mapping.
JSON body examples:
Set mapping:
{"action":"set","name":"api","port":3000}Delete mapping:
{"action":"delete","name":"api"}Proxy route /<internal_port>/<path...>
Conduit validates internal_port is listening, then proxies the request.
Proxy route /<app_name>/<path...>
Conduit resolves app_name from settings, validates mapped port is listening, then proxies the request.
HTTP Interface
When conduit runs normally, it starts one HTTP server that provides:
- Proxy routes (
/<port>/...,/<app>/...) - API endpoints (
/health,/ports,/apps) - Dashboard UI (
/ui)
Run with -no-http (or -no-ui) to disable the HTTP server and use CLI-only workflows.
Testing
Notes
- HTTP reverse proxy behavior preserves query params, request body, and standard headers/cookies (except normal hop-by-hop header stripping).
- Linux-oriented port discovery via
/proc/net/tcpand/proc/net/tcp6. - In containers, publish/forward Conduit’s single public port (for example
9000:9000).
