HubTunnels

HubTunnels give you temporary private access to containers inside a Hubfly project without publishing those services to the internet. A tunnel maps a port on your local machine to a private container port through an authenticated SSH forwarding path, so you can connect to databases, internal dashboards, admin tools, and debugging endpoints from localhost.

Use HubTunnels when a service should stay private, but a developer, operator, or support engineer needs short-lived access from their machine.

HubTunnels are for private access, not public ingress. Use public HTTP endpoints, custom domains, load balancers, and Firewall for production user traffic. Use HubTunnels for administrative, debugging, and maintenance access.

What HubTunnels do

HubTunnels create an authenticated port forward into a project network.

CapabilityWhat it doesCommon use case
Local port forwardingMaps localhost:<local_port> to a private container portConnect a local database client to private Postgres
Temporary accessTunnels expire by default after 1 hourMaintenance windows, debugging, support sessions
Project-scoped accessRequires project ownership or membershipPrevents users from tunneling into projects they cannot access
Container targetingTunnels to one selected container and portReach postgres:5432, redis:6379, or api:8080 privately
SSH transportUses SSH forwarding with generated keysStandard, familiar private access model
Dashboard and API visibilityLists active tunnels and tunnel instructionsOperational awareness and cleanup
Local service syncStarts or reconnects the local tunnel serviceKeeps server tunnel records and local forwarding aligned

When to use HubTunnels

Use HubTunnels for services that should not have a public endpoint.

Good fits include:

  • PostgreSQL, MySQL, Redis, MongoDB, and other private databases
  • Internal admin dashboards
  • Private HTTP APIs
  • Debug ports and development-only endpoints
  • Maintenance access for production services
  • One-off data inspection from local tools
  • Temporary support access during incidents
  • Preview systems that should not be internet-visible

Do not use HubTunnels as a substitute for production ingress. If users or customers need stable access, use an HTTP endpoint, custom domain, load balancer, and Firewall rules instead.

How HubTunnels work

A HubTunnel has two sides:

SidePurpose
Server-side tunnelA short-lived SSH-accessible tunnel container attached to the project network
Local tunnel service or SSH clientRuns on your machine and forwards a local port to the target container port

The flow is:

  1. You authenticate with Hubfly through the CLI, dashboard, or API key.
  2. Hubfly verifies that you own or belong to the project.
  3. You select a project, container, and target port.
  4. Hubfly creates a temporary tunnel endpoint inside the project’s private network.
  5. The local tunnel service or SSH command maps a local port to the private container port.
  6. Your local client connects to localhost:<local_port>.
  7. Traffic is forwarded to the private container without creating public ingress for that service.
  8. The tunnel is stopped manually or removed after expiration cleanup.

Requirements

RequirementWhy it matters
Hubfly account accessTunnel creation is authenticated
Project ownership or membershipTunnels are scoped to projects you can access
Target container in the selected projectThe tunnel must know which private service to reach
Target portThe private port to forward, such as 5432, 6379, or 8080
Available local portThe local machine port must not already be in use
Local tunnel service or SSH clientRequired to create the local forwarding session

Dashboard-created tunnels use the local tunnel service on localhost:5600. If that service is not running, the server-side tunnel can be created but local forwarding will not start until you sync it locally.

Tunnel lifetime

HubTunnels are temporary. The default TTL is 3600 seconds, or 1 hour.

The platform stores an expiration time for each tunnel and a cleanup route removes expired tunnel records and their backing tunnel containers. Manual stop also deletes the backing tunnel container and removes the tunnel record.

Do not design production workflows around a HubTunnel being permanently available. Tunnels are intentionally short-lived private access paths.

Ports and addressing

A tunnel has several port values:

ValueMeaning
Target portThe port inside the target container, such as 5432
SSH portTemporary public SSH port allocated for the tunnel endpoint
Local portThe port on your machine, such as localhost:5432
Remote hostThe target container’s internal IP or Docker name inside the project network

Hubfly allocates server-side SSH ports from the tunnel port range starting at 40000 and up to 40500. If all active tunnel ports are used, creating a new tunnel can fail with no available tunnel ports.

The local port is your choice. It can match the target port, but it does not have to. If 5432 is already used locally, forward remote Postgres to a different local port such as 15432.

Create a tunnel with the CLI

The CLI flow is the simplest path for most developers.

hubfly tunnel create --project <project_id> --container <container_id> --port 5432 --local 5432

This maps your local port 5432 to the target container’s port 5432.

Then connect with a local client:

psql -h localhost -p 5432 -U postgres postgres

For a private HTTP service:

hubfly tunnel create --project <project_id> --container <container_id> --port 8080 --local 3000

Then open:

http://localhost:3000

List and stop tunnels

Use the CLI to see active tunnels and stop them when the session is done.

hubfly tunnel list
hubfly tunnel stop <tunnel_id>

Stop tunnels after the task is complete. This reduces open access paths, cleans up tunnel containers, and avoids stale operational state.

Use the dashboard Tunnel Manager

The dashboard includes a Tunnel Manager for users who want a guided UI flow.

The dashboard flow is:

  1. Open the Tunnel Manager.
  2. Confirm the local tunnel service is running on localhost:5600.
  3. Select a project.
  4. Select a container in that project.
  5. Enter the private target port.
  6. Start the tunnel.
  7. Connect to the local port shown in the active tunnel list.
  8. Stop the tunnel when finished.

The active tunnel list shows:

  • Target container name
  • Running Locally or Server Only status
  • Remote target address and port
  • Local port when connected locally
  • SSH host and SSH port
  • Stop action
  • Sync to Local action when the server-side tunnel exists but local forwarding is not running

Server Only vs Running Locally

StatusMeaningAction
Running LocallyThe local tunnel service is forwarding traffic on your machineConnect to localhost:<local_port>
Server OnlyThe server tunnel exists, but local forwarding is not activeUse Sync to Local or create the SSH forward manually

This split is useful when the browser created a tunnel but the local service was down, restarted, or lost the forwarding session.

Manual SSH forwarding

API responses and tunnel listings can include an SSH command pattern similar to:

ssh -p <ssh_port> -i <your-private-key> -L <local_port>:<remote_host>:<target_port> root@<ssh_host> -N

Example:

ssh -p 40000 -i ./hubfly-tunnel-key \
  -L 15432:postgres.internal:5432 \
  root@203.0.113.10 -N

Then connect locally:

psql -h localhost -p 15432 -U postgres postgres

Use manual SSH forwarding when you want to integrate with your own SSH tooling or when the local tunnel service is not available.

API workflow

HubTunnels can also be created and listed through API endpoints for tooling and automation.

Create a tunnel:

curl -X POST https://hubfly.space/api/tunnels \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "<project_id>",
    "containerId": "<container_id>",
    "targetPort": 5432,
    "publicKey": "ssh-rsa ...",
    "ttlSeconds": 3600
  }'

List your tunnels:

curl https://hubfly.space/api/tunnels \
  -H "Authorization: Bearer <api_key>"

List tunnels for a project:

curl https://hubfly.space/api/projects/<project_id>/tunnels \
  -H "Authorization: Bearer <api_key>"

API-created tunnels return connection details such as tunnel ID, SSH host, SSH port, SSH user, expiration time, and SSH forwarding instructions.

Database access examples

PostgreSQL

hubfly tunnel create --project <project_id> --container <postgres_container_id> --port 5432 --local 5432
psql -h localhost -p 5432 -U postgres postgres

If local Postgres is already using port 5432:

hubfly tunnel create --project <project_id> --container <postgres_container_id> --port 5432 --local 15432
psql -h localhost -p 15432 -U postgres postgres

MySQL

hubfly tunnel create --project <project_id> --container <mysql_container_id> --port 3306 --local 3306
mysql -h 127.0.0.1 -P 3306 -u root -p

Redis

hubfly tunnel create --project <project_id> --container <redis_container_id> --port 6379 --local 6379
redis-cli -h 127.0.0.1 -p 6379

Private HTTP examples

Internal admin panel

hubfly tunnel create --project <project_id> --container <admin_container_id> --port 8080 --local 8080

Open:

http://localhost:8080

Private API debugging

hubfly tunnel create --project <project_id> --container <api_container_id> --port 3000 --local 13000
curl http://localhost:13000/health

This lets you test the internal service from your machine without adding a public endpoint or custom domain.

HubTunnels vs public endpoints

Use HubTunnels whenUse public endpoints when
Access is temporaryAccess must be stable and user-facing
The service is privateThe service is intended for public traffic
A developer or operator needs accessCustomers, browsers, or external systems need access
You are connecting to a database/admin portYou are serving HTTP traffic with domains and SSL
You want no DNS or public ingress setupYou need DNS, SSL, redirects, headers, or Firewall

For production, the safer default is: keep internal services private, expose only public apps, and use HubTunnels for administrative access.

HubTunnels and databases

HubTunnels are the recommended access path for private databases.

Production database pattern:

  1. Deploy the database without a public endpoint.
  2. Let application containers connect over the private project network.
  3. Use HubTunnels for human administrative access.
  4. Stop the tunnel after inspection, migrations, backups, or debugging.
  5. Keep database credentials separate from tunnel credentials.

A tunnel does not replace database authentication. It only creates the network path. The database should still require its normal username, password, certificate, or application-level authentication.

HubTunnels and Compose stacks

Compose services often include databases, queues, caches, workers, and internal APIs. Most of those should stay private.

Use HubTunnels to reach:

  • postgres:5432 for migrations or inspection
  • redis:6379 for debugging keys or connection behavior
  • minio:9001 for private admin access
  • internal APIs that should not receive internet traffic
  • workers with debug or metrics ports

Avoid exposing internal Compose services publicly just because a developer needs temporary access.

Security best practices

Follow these practices when using HubTunnels:

  • Keep tunnels short-lived.
  • Stop tunnels when maintenance is complete.
  • Use project membership carefully because members can create tunnels into containers they can access.
  • Do not share generated private keys, SSH commands, or tunnel details in public channels.
  • Use database credentials, application authentication, and least-privilege users even through a tunnel.
  • Avoid tunneling to destructive admin tools unless the operator needs that access.
  • Prefer non-default local ports when they reduce confusion with local services.
  • Keep production databases private and use tunnels only for administrative access.
  • Audit active tunnels during incident response or sensitive maintenance.

Operational best practices

For teams:

  • Document which ports are safe to tunnel for each service.
  • Use separate database users for administrative tunnel access.
  • Avoid long-running tunnels on laptops.
  • Stop and recreate tunnels instead of relying on stale sessions.
  • Keep internal dashboards behind authentication even when accessed through a tunnel.
  • Use local port names consistently, such as 15432 for remote Postgres when local Postgres already uses 5432.
  • Prefer project-bound private networking for service-to-service traffic; tunnels are for human or local-tool access.

Monitoring and cleanup

Use tunnel lists to understand who has active access paths and what they target. Expired tunnels are cleaned up by the platform cleanup flow, and manual stop removes the tunnel container and database record.

If a tunnel appears stale:

  1. Refresh the tunnel list.
  2. Stop the tunnel from the CLI or dashboard.
  3. If local forwarding still appears active, stop it in the local tunnel service.
  4. Recreate the tunnel only if access is still needed.

Troubleshooting

SymptomLikely causeWhat to do
Local Tunnel Service is not detectedThe local service on localhost:5600 is not runningStart the tunnel service or use manual SSH forwarding
Tunnel is Server OnlyServer-side tunnel exists but local forwarding is not activeUse Sync to Local and choose a local port
Local port is already in useAnother process uses that portChoose a different local port, such as 15432 instead of 5432
Project is missingYou are not the owner or project memberConfirm project access and account context
Container list is emptyNo containers exist in the project or access is missingDeploy the target container or verify permissions
Connection refused through tunnelTarget service is not listening on the target portCheck the container port, process, and service logs
Authentication failsTunnel works but database/app credentials are wrongVerify database credentials or application login
No available tunnel portsActive tunnel SSH port range is exhaustedStop unused tunnels and retry
Tunnel expiredDefault TTL elapsed and cleanup removed itCreate a new tunnel
SSH command failsWrong key, SSH port, host, or expired tunnelRegenerate the tunnel and use the current instructions

FAQ

Are HubTunnels public endpoints?

No. HubTunnels are private access paths for authenticated operators. They do not create a public HTTP endpoint, custom domain, or load balancer route for the target service.

How long do tunnels last?

The default lifetime is 1 hour. Tunnels can also be stopped manually before they expire.

Can I use HubTunnels for production database access?

Yes. This is the recommended pattern for human access to private production databases. Keep app-to-database traffic on the private project network and use tunnels only for administrative sessions.

Do HubTunnels replace database passwords?

No. A tunnel gives network reachability. Your database, API, or dashboard should still enforce its own authentication and authorization.

Can I choose a different local port?

Yes. The local port can differ from the target port. This is useful when your laptop already has a service using the default port.

What happens if my laptop disconnects?

The server-side tunnel may still exist until it expires or is stopped. Reconnect with Sync to Local, manual SSH, or create a new tunnel if needed.

Should I use HubTunnels for customer traffic?

No. Use public endpoints, domains, load balancers, SSL, and Firewall for customer-facing traffic. HubTunnels are for temporary private access.

Can project members create tunnels?

Yes, if they have access to the project. Tunnel creation verifies project ownership or membership before creating the tunnel.

Feedback

Was this page helpful?

Tell us whether this page helped you complete the task you came here for.