Evaluate a Compose tunnel companion without inventing unsupported container commands
Running a tunnel client beside a development application can separate public connectivity from application code and make the intended topology easier to review. However, an evidence-backed Localtonet container image, supported container installation path, noninteractive authentication method, startup invocation, and automatic tunnel provisioning command are not available in the verified product information used for this guide. This article is therefore an architecture and feasibility guide, not a copy-and-run Dev Container implementation. It explains the prerequisites, network model, HTTP tunnel workflow, validation sequence, security controls, operational tasks, and product details that must be confirmed before a Localtonet companion service can be approved.
π What's in this guide
Support status and the boundary of this guide
The verified Localtonet information available for this revision does not identify an official Localtonet container image, a supported installation command for an arbitrary container base, a noninteractive client startup command, a documented environment variable for authentication, or a command that creates and starts an HTTP tunnel from inside a container. It also does not confirm whether the HTTP tunnel target field accepts a Docker DNS name such as app instead of an IP address. Publishing a Dockerfile, Compose service, or devcontainer.json that assumes those details would turn an architectural proposal into an unsupported implementation.
Localtonet is a multi-protocol tunneling and proxy platform. Our client establishes an outbound connection from the device on which it runs to a Localtonet relay server. A running tunnel then provides a public URL or a public host and port for a service reachable from that client. This avoids inbound router port forwarding, firewall changes, VPN setup, and the requirement for a public IP address.
Those verified platform properties make a container companion architecture plausible, but plausibility is not the same as official container support. A true implementation requires more than placing an executable in a second service. The client must install successfully in the selected base image, authenticate without exposing its device token, remain running as the container's managed process, reach the application target, reconnect in a documented way after recreation, and interact correctly with the tunnel lifecycle in our dashboard.
Before publishing or adopting an exact implementation, confirm all of the following against current first-party Localtonet documentation, the current client release, and the dashboard:
- Whether running the Localtonet client inside a Linux container is currently supported.
- Which base distributions and CPU architectures are supported.
- The current installation package, image, or installation command.
- The documented noninteractive authentication and client startup behavior.
- How a device-specific token may be supplied without placing it on a command line or in an image layer.
- Whether an HTTP tunnel target accepts a Compose service name or requires a literal local IP address.
- Whether tunnel creation can be automated through a supported client interface or the REST API.
- Whether an existing tunnel can be associated reliably with a recreated container client.
- Whether starting the client also starts a tunnel, or whether the tunnel must still be started separately.
- How generated, selected, and custom-domain endpoints behave after a Dev Container rebuild.
Until those points are confirmed, use this guide to review the design and build a verification plan. Do not infer Localtonet commands, environment variable names, API payloads, image tags, dashboard fields, or endpoint guarantees from examples written for other tunnel products.
What the companion-service architecture changes
In this design, the application container owns the web server, API, webhook receiver, or callback handler. A separate Compose service would run the Localtonet client and provide public connectivity. The application would not contain Localtonet installation or tunnel management logic, and the tunnel service would not need the application source code unless the chosen implementation introduced an additional requirement.
This separation creates a useful review boundary. The application team can define which interface and port the development server uses. The connectivity configuration can define which single service should become public, which device identity runs the client, and when the tunnel should be stopped. Credentials can be managed separately from the application image.
Compose companion service versus Kubernetes native sidecar
The word sidecar is often used informally for both designs, but their networking and lifecycle behavior differ. A Docker Compose companion is normally a separate container with its own network namespace. It reaches another service through a shared Docker network, typically using container networking and service discovery rather than the companion's loopback address.
A Kubernetes native sidecar is a secondary container in the same Pod as the application. Containers in one Pod share the Pod network namespace, so they can communicate through the Pod's loopback interface. Kubernetes implements native sidecars as restartable init containers, and current Kubernetes documentation describes their startup and Pod termination behavior separately from ordinary application containers.
| Property | Docker Compose companion | Kubernetes native sidecar |
|---|---|---|
| Placement | Separate Compose service and container | Secondary container in the same Pod |
| Network namespace | Normally separate from the application container | Shared at the Pod level |
| Meaning of localhost | Refers to the companion container itself | Can reach another container's listener through the shared Pod network namespace |
| Application address | Normally a service name or network address plus the container port | Often a loopback address plus the application port |
| Lifecycle control | Managed through Compose service lifecycle and dependencies | Managed by Kubernetes Pod and native sidecar lifecycle rules |
This article concerns the Compose model used by Dev Containers. A Kubernetes manifest should not be produced by mechanically translating the Compose topology because the address, readiness, restart, and termination assumptions are different.
Prerequisites for an evidence-backed implementation
Do not begin by writing a tunnel service definition. First establish that the development application and the proposed client environment satisfy the prerequisites below.
Container tooling
- A working Docker installation capable of building and running the project's selected images.
- Docker Compose support for the Compose file used by the project.
- A Dev Container capable editor or CLI that can open the Compose-backed development environment.
- Permission to inspect service status and logs and to execute diagnostic commands in running containers.
Verify the local tools before diagnosing the application or Localtonet:
docker version
docker compose version
A reachable development application
The application must already start successfully without the tunnel. It needs a stable container port and a test route, preferably a lightweight health endpoint that does not mutate data. The process must listen on an interface reachable from the Compose network. A service bound only to 127.0.0.1 inside the application container may work from that same container while rejecting traffic from a companion container.
The precise command for binding to a container-reachable interface depends on the framework. Do not copy a flag from an unrelated runtime. Confirm the framework's documented listen-host setting and apply authentication or development-only safeguards where appropriate.
A Localtonet account and device identity
You need a Localtonet account and a device-specific authentication token for the client that would run in the companion container. Tokens identify client devices and must not be guessed, shared casually, committed, printed in examples, or stored in image layers.
The design also requires a currently available relay server or region selected from the Localtonet product or dashboard. Available values must be obtained at configuration time. Do not hardcode a server code from an old article.
A supported Localtonet client path for the selected base
This is the unresolved prerequisite that prevents this article from providing a runnable implementation. Before choosing a base image, obtain current first-party confirmation of the supported client installation method, runtime dependencies, CPU architecture, authentication behavior, process invocation, and container support.
Tunnel products use different images, token variables, commands, lifecycle models, and endpoint semantics. Renaming another product's service to localtonet does not create a valid Localtonet implementation. It can also expose a device token to an unsupported process or create a false expectation that a tunnel will be provisioned automatically.
Plan the project layout before adding implementation details
A Compose-backed Dev Container project commonly keeps its development environment definition under .devcontainer. The following tree is a planning model, not a runnable Localtonet project:
project/
βββ .devcontainer/
β βββ devcontainer.json
β βββ docker-compose.yml
β βββ Dockerfile
βββ src/
βββ .gitignore
βββ README.md
Each file has a distinct responsibility:
devcontainer.jsonidentifies the Compose configuration, the development service opened by the editor, and the workspace location.docker-compose.ymldescribes the application service, networks, health behavior, and the proposed Localtonet companion service.Dockerfileis needed only when the application or companion requires a custom image. A companion Dockerfile must not be written until a supported Localtonet installation path is confirmed..gitignoremust exclude any local environment or secret files used by the approved workflow.README.mdshould explain prerequisites, startup, verification, shutdown, token rotation, and rebuild behavior after those details are tested.
What a future Compose definition must express
An approved Compose implementation would need an application service and a separate Localtonet service attached to the same intended network. The application service should expose its internal listener to that network and include a health check that reflects actual readiness. The Localtonet service would need a verified image or build, a supported startup command, a secret input, and a restart policy appropriate for the client.
A startup dependency can prevent the tunnel companion from starting before the application container, but container startup alone is not application readiness. If the selected Compose implementation supports health-based dependency conditions, the application's health check should test the exact internal route and port the tunnel will use. The test utility must also exist in the application image.
We intentionally do not provide placeholder Localtonet values such as LOCALTONET_TOKEN, a fictional image name, or an invented client command. Even visibly fake names can be copied into production configuration and misrepresented as supported interfaces.
Secret handling and Dev Container configuration
Keep the device token outside the repository and outside Docker build arguments. Build arguments and Dockerfile environment instructions can persist in image metadata or layers. Avoid putting the token directly into docker-compose.yml or devcontainer.json, even in a private repository.
Dev Container tools can participate in passing host or managed-environment configuration to Compose, but the exact syntax and precedence depend on the current Dev Container implementation and launch path. Before choosing a method, verify it against the current primary Dev Container and Docker Compose documentation used by the team. Confirm that the value reaches only the Localtonet service, is not expanded into committed output, and is not displayed by routine diagnostics.
Also confirm how the Localtonet client accepts its token. A secret mounted as a file is useful only if the supported client can read that file or an entrypoint can pass it without leaking it. An environment secret is useful only if the client documents that authentication method. Do not invent a token environment variable.
Even if Compose or a Dev Container tool can inject a value, that does not prove the Localtonet client supports the resulting variable, file, or command-line form. Container configuration and Localtonet authentication must both be documented and tested.
Why localhost fails between Compose services
Each ordinary Docker container has its own network namespace. Inside the application container, 127.0.0.1:3000 refers to port 3000 in that application container. Inside a separate tunnel container, the same address refers to port 3000 in the tunnel container.
That explains a common diagnostic contradiction: the application responds from its own terminal, but the companion cannot connect. Both observations can be accurate because they test different loopback interfaces. Publishing port 3000 to the Docker host may allow host access, but host publication is not normally the path used for communication between two services on a shared Compose network.
At the Docker networking layer, a companion commonly resolves the application by its Compose service name. If the service is named app and listens on container port 3000, the conceptual destination is app:3000. This does not yet prove that the Localtonet HTTP tunnel configuration accepts app as its local target. Our verified product context describes HTTP targets as a local IP address and port, so hostname acceptance must be confirmed before this architecture is declared runnable.
Container addresses can change when services or networks are recreated. Assigning a static container address introduces additional network management and still does not establish that the Localtonet client-in-container design is supported. Confirm the product's accepted target format instead of relying on an accidental address observed during one run.
Application binding
DNS resolution is only the first part of connectivity. The application must accept traffic arriving through its container interface. If it listens only on loopback, a connection to its network address can fail with βconnection refusedβ even while an in-container loopback test succeeds.
Bind the development server to an interface intended for container-network access, using the framework's documented option. This does not mean every port should be published to the host or exposed publicly. Keep the service on the narrowest suitable Docker network, publish host ports only when required, and expose only the one application target selected for the tunnel.
Exact Localtonet workflow for the proposed HTTP scenario
The example architecture is a browser-facing web application or HTTP API. It therefore calls for an HTTP/s tunnel rather than File Server, a proxy configuration, or VPN Manager. File Server publishes a folder path, proxy tunnels make the connected device an exit node, and VPN Manager provides private mesh VPN functionality. None of those is a replacement for forwarding requests to this example application.
The documented product sequence for the HTTP scenario is:
Install and run the Localtonet client
Run the client on the device that can reach the HTTP application. In the proposed architecture this would be the companion container, but that placement must not proceed until the container installation and invocation are confirmed as supported.
Authenticate or select the device
Use the device-specific authentication token for the client intended to run the tunnel. Keep it out of the image, repository, example configuration, screenshots, shell history, and logs.
Select an available relay server
Select a current server or region from the Localtonet product or dashboard. Do not hardcode undocumented server codes because availability can vary.
Create an HTTP tunnel for the application target
Choose the HTTP tunnel family and configure the application's local target and container port. For this architecture, confirm first whether the target can be the Compose service name or must be an IP address reachable from the client.
Start the tunnel
Creating a tunnel does not make it run. Start it with the Start control after the selected client is connected, then use the assigned public HTTPS address.
Stop or delete it after the test
Stop the tunnel when public access is no longer required. Delete it if its configuration should not be retained. Compose teardown does not by itself prove that the dashboard tunnel has been stopped or deleted.
HTTP tunnels may use a generated subdomain, a selected subdomain where supported, or a custom domain. These Process Type options serve the same content at a public HTTPS address. Exact custom-domain DNS steps and endpoint persistence must be checked against current documentation before a callback URL or webhook sender is configured around a fixed address.
Validate every layer before testing the public endpoint
1. Validate the application service
Start the application independently and inspect its state:
docker compose up -d app
docker compose ps
docker compose logs --tail=200 app
Use the application's documented local test command inside the application container. For example, if the image contains an HTTP client and the application provides a health route, test its loopback listener. Replace the port and path with the project's real values:
docker compose exec app curl -fsS http://127.0.0.1:3000/health
This command is applicable only if curl exists in the application image. Otherwise use an HTTP client already supplied by the runtime or image. A successful loopback response proves that the application process is listening, but it does not prove companion-container connectivity.
2. Validate from the proposed tunnel container
Once a supported Localtonet companion image exists, check Docker DNS and the application route from that container:
docker compose exec tunnel getent hosts app
docker compose exec tunnel curl -fsS http://app:3000/health
These diagnostics require getent and curl in the companion image. If they are absent, use supported tools included in that image or a temporary diagnostic container attached to the same network. Do not modify a production-oriented Localtonet image merely to hide a network problem.
A DNS failure points to a service-name or network attachment problem. A resolved address followed by βconnection refusedβ usually points to application binding, the wrong port, or a process that is not ready. A timeout can indicate a network mismatch, an application that accepts no traffic, or another filtering condition.
3. Validate the Localtonet client and tunnel state
Confirm in the Localtonet dashboard that the selected device is connected. Then confirm that the intended HTTP tunnel exists and is running. These are separate states. A connected client does not mean every tunnel is active, and a saved tunnel does not mean its selected client is connected.
Inspect the companion logs without printing secrets:
docker compose logs --tail=200 tunnel
docker compose logs -f tunnel
The exact successful connection message is client-version specific and is not asserted here. Review the current client's documented output. If logs reveal credentials or a private endpoint, stop sharing them and correct the logging or invocation method before continuing.
4. Validate the assigned public endpoint externally
Test the assigned HTTPS URL from outside the Compose network, such as a browser or HTTP client on another connection. Use a distinctive health or version route so a cached page cannot create a false positive. Verify the expected status code, response body, application log entry, and request path.
For webhook testing, verify the method, request path, response status, signature, replay handling, and duplicate-delivery behavior. For OAuth, register the exact assigned callback URL and preserve state validation. For WebSockets, test the complete upgrade and message flow rather than assuming that a successful page load proves WebSocket connectivity.
Expose only the intended development route and service. Keep databases, administration panels, debug consoles, metrics endpoints, and unrelated ports private. Require application authentication and authorization where appropriate, validate webhook signatures, apply least privilege, use IP restrictions where available and suitable, and keep tunnel lifetimes short. Never use a tunnel to bypass organizational policies or required security controls.
Startup, logs, rebuilds, shutdown, and credential rotation
Start and inspect the Compose project
Before startup, render and review the effective Compose configuration:
docker compose config
docker compose up -d
docker compose ps
Treat the output of docker compose config as potentially sensitive if the chosen interpolation method expands secret values. Do not paste it into tickets or public logs until you have confirmed that credentials are absent or redacted.
After services start, inspect application and tunnel logs separately:
docker compose logs --tail=200 app
docker compose logs --tail=200 tunnel
Restart only the companion
If the client process fails while the application remains healthy, restart the companion independently:
docker compose restart tunnel
docker compose ps
docker compose logs --tail=200 tunnel
Then recheck device connectivity and tunnel status in the Localtonet dashboard. Do not assume the restarted client automatically starts a saved tunnel.
Rebuild the Dev Container deliberately
A Dev Container rebuild may recreate the application container, companion container, network, or all three. Before rebuilding, record the tunnel identifier and intended public endpoint without recording the token. After rebuilding, repeat local application, inter-container, client-state, tunnel-state, and external endpoint checks.
Do not assume the public URL remains unchanged. If it changes, update OAuth redirect registrations, webhook destinations, test clients, CORS allowlists, cookie configuration, and any frontend environment value that embeds the public origin.
Stop exposure separately from Compose teardown
Stop the Localtonet tunnel through the documented product control when public access is no longer needed. Then stop the Compose project:
docker compose down
If the tunnel configuration should not be retained, delete it separately. A container stopping makes the tunnel unavailable because its selected client is disconnected, but that does not necessarily delete the saved tunnel configuration.
Rotate or revoke a device token
Rotate or revoke credentials whenever a token may have appeared in source control, an image layer, shell history, logs, screenshots, support bundles, or an unapproved secret store. Remove the exposed copy from the runtime and repository history as required by your incident process. Supply the replacement through the approved secret mechanism, recreate the companion, and verify that the previous credential no longer connects.
Avoid assigning one device token casually across unrelated developers or projects. Device identity, ownership, revocation responsibility, and offboarding should be explicit.
Troubleshooting the proposed sidecar path
The application service name does not resolve
Inspect the effective configuration and network attachments:
docker compose config
docker compose ps
docker compose exec tunnel getent hosts app
docker network ls
Confirm that the service is actually named app in the effective Compose model and that both services join the same intended network. Project overrides can change service configuration. If getent is unavailable, use another DNS lookup tool already present in the image.
The connection is refused
Compare a loopback check from the application container with a network check from the companion:
docker compose exec app curl -fsS http://127.0.0.1:3000/health
docker compose exec tunnel curl -v http://app:3000/health
If the first succeeds and the second is refused, inspect the application's listen address. It may be bound only to loopback. Also confirm that 3000 is the container port rather than an unrelated host-published port.
The wrong port is configured
Review application startup logs and the effective Compose configuration:
docker compose logs --tail=200 app
docker compose config
Container-to-container traffic uses the application's container listener port. A host mapping such as host port 8080 to container port 3000 does not mean the companion should target port 8080.
The services are on different networks
Inspect the running containers and project networks:
docker compose ps
docker network ls
docker inspect <app-container-name>
docker inspect <tunnel-container-name>
Replace the placeholders with names shown by docker compose ps. Avoid publishing complete inspection output if it includes environment values or credentials.
The application dependency is unhealthy
Check service state and health-related logs:
docker compose ps
docker compose logs --tail=200 app
Run the health-check command manually inside the application container. Confirm that its utility exists, route is correct, startup period is sufficient, and response accurately represents readiness. A dependency declaration cannot repair an incorrect health test.
The Localtonet client is disconnected
Inspect the companion status and logs, then verify the device state in the dashboard:
docker compose ps tunnel
docker compose logs --tail=200 tunnel
docker compose restart tunnel
Check for an expired or revoked token, an unsupported client environment, startup failure, outbound connectivity problems, or a recreated container that no longer maps to the expected device identity. Use only documented Localtonet authentication and invocation methods.
The client is connected but the public endpoint fails
Check whether the HTTP tunnel itself is running. Creating it is not enough. Then repeat the application-container and companion-container health tests. A connected device with a stopped tunnel produces a different failure from a running tunnel whose local target is unavailable.
A callback or webhook stopped working after rebuild
Compare the current assigned public URL with the URL registered at the external provider. If it changed, update the exact callback or destination. Recheck scheme, hostname, port, path, CORS behavior, cookie security, OAuth redirect matching, and webhook signature configuration. Do not promise stable endpoint persistence until it has been verified for the selected Process Type and current product behavior.
Frequently asked questions
Does Localtonet currently provide a verified official container image for this guide?
No official image is identified in the verified product information available for this revision. This guide therefore does not invent an image name or tag. Confirm current first-party container support before implementing the companion service.
Why is there no complete Dockerfile or docker-compose.yml?
A valid Dockerfile and Compose service require a supported client installation path, base image, startup command, authentication method, and target format. Those Localtonet-specific facts are not confirmed in the supplied evidence. Publishing placeholders would misrepresent an architectural proposal as a runnable implementation.
Why can a Compose companion not reach the application through localhost?
Separate Compose containers normally have separate network namespaces. Localhost inside the companion points back to the companion. Docker-level communication normally uses a shared network and the application's service name or network address, but Localtonet acceptance of a service-name target must still be confirmed.
Is a Compose companion the same as a Kubernetes native sidecar?
No. A Compose companion is normally a separate container and network namespace. Kubernetes containers in the same Pod share the Pod network namespace, and native sidecars have Kubernetes-specific startup, restart, readiness, and termination behavior.
Does creating a Localtonet HTTP tunnel automatically make it public?
No. The selected client must be connected and the tunnel must be started. Creation, client connectivity, and tunnel running state are separate lifecycle conditions.
Should the device token be stored in devcontainer.json or docker-compose.yml?
No. Keep the device-specific token out of committed configuration, image layers, build arguments, logs, and screenshots. Use an approved runtime secret mechanism only after confirming how the current Localtonet client supports authentication.
Will the public HTTPS address survive a Dev Container rebuild?
Do not assume that it will. Endpoint behavior can depend on the tunnel configuration, Process Type, current dashboard behavior, client identity, and available options. Verify persistence before relying on a fixed OAuth callback, webhook destination, or browser origin.
Is this HTTP tunnel a VPN?
No. An HTTP tunnel exposes a selected HTTP application target. VPN Manager is our separate private mesh VPN feature.
Validate Localtonet container support before building the sidecar
Map the application listener, Compose network, HTTP target, device identity, secret boundary, rebuild behavior, and shutdown policy. Proceed to an exact Dockerfile and Compose implementation only after the current Localtonet client installation, authentication, startup, target format, and endpoint behavior have been confirmed.
Get Started Free β