28 min read

Set Up openGym with Passkeys and Localtonet

Install and verify openGym with Docker Compose, configure domain-based passkeys, then enable secure remote browser access with Localtonet over HTTP.

Self-Hosting ยท openGym ยท Passkeys ยท Localtonet ยท 2026

Run your workout tracker locally, bind passkeys to its final web identity, and make the verified service reachable from your devices

openGym is a self-hosted gym and body-weight tracker that can synchronize profiles, routines, workouts, and progress across devices. This guide follows the project's Docker Compose quick start, verifies the local service at http://localhost:8080, maps a final public hostname to the exact RP_ID and ORIGIN formats required for passkeys, and connects the working application to a Localtonet HTTP tunnel. The order changes slightly depending on whether you already know the public hostname or need Localtonet to assign one. HTTPS protects browser traffic in transit, while openGym remains responsible for authenticating users and authorizing access to their data.

๐Ÿ”’ Exact RP ID and browser-origin alignment ๐ŸŒ Local openGym service on port 8080 by default โšก No inbound router port forwarding required
A remote phone connects through an HTTP tunnel to openGym running locally in Docker, with passkey authentication handled by openGym.
openGym runs locally in Docker, while Localtonet carries remote HTTPS requests to the verified web service.

How an openGym and Localtonet deployment works

Remote browsers reach a Docker-hosted openGym service through a Localtonet HTTP tunnel.
The HTTP tunnel maps a public HTTPS address to openGym's host-published web port without publishing the other application components.

openGym is a self-hosted web application for planning routines, running guided workouts, recording sets and body weight, and reviewing training progress. Its self-hosted edition keeps application data on infrastructure you control while making a profile available across your devices. The project supports passkey profile sign-in, optional password sign-in when enabled for an instance, one-time-code or QR pairing for new devices, and JSON data export.

The documented quick start uses Docker with the Docker Compose plugin. The official openGym repository contains the Compose deployment and example environment file. The sequence clones the repository, enters its directory, copies .env.example to .env, pulls the published images, and starts the stack. With the documented defaults, the browser endpoint is http://localhost:8080.

Local and public connectivity are different layers. Docker Compose starts openGym and publishes its web service on the host. The Localtonet client then establishes an outbound connection to one of our relay servers and maps a public HTTPS address to that working HTTP endpoint. This approach does not require an inbound router port-forwarding rule, a public IP address, firewall changes for inbound internet traffic, or a separate VPN.

The tunnel does not authenticate an openGym profile or decide which profile data a visitor may use. It provides reachability and an HTTPS public endpoint. openGym must still perform its own authentication and authorization, including the server-side validation required by WebAuthn.

๐Ÿ‹๏ธ Self-hosted workout data openGym keeps the self-hosted application's data on infrastructure under your control and can synchronize profiles across devices.
๐Ÿณ Docker Compose deployment The official quick start uses the repository's Compose file and published container images for amd64 and arm64.
๐Ÿ”‘ Domain-bound passkeys Passkey registration and sign-in are tied to a relying-party domain and validated browser origin rather than acting like reusable passwords.
๐Ÿ”’ Public HTTPS origin A remote device reaches openGym through an HTTPS address that must agree with the application's passkey configuration.
๐ŸŒ Outbound tunnel connection The Localtonet client connects outward to our relay and forwards requests to the selected local IP address and port.
๐Ÿ“ฑ Cross-device access Once networking and authentication are configured, compatible phones and computers can use the same self-hosted instance.

Understand the three relevant addresses

Each layer has a different address. Containers communicate according to the repository's Compose configuration. The Docker host publishes the web service on port 8080 by default. Remote browsers use the public HTTPS hostname assigned or configured for the Localtonet tunnel. Passkey settings must describe that final browser-visible identity, not a Docker-internal address and not the local development URL.

Layer Address or identity Purpose
Compose network Managed by the repository's Compose configuration Connects openGym components inside the Docker deployment.
Docker host http://localhost:8080 by default Provides the first endpoint to test before adding public access.
Public browser origin The final Localtonet HTTPS address Lets remote browsers reach openGym and supplies the identity used for passkey configuration.
Prove each layer independently

Start openGym and verify http://localhost:8080 before creating a tunnel. After you know the final public hostname, configure RP_ID and ORIGIN, recreate the application services, and then perform the final public and passkey tests. This sequence prevents a Docker failure from being mistaken for a tunnel or WebAuthn problem.

Prerequisites

Use a machine that can remain powered on whenever openGym should be available. The application containers must be running, and public access also depends on the selected Localtonet client being connected and the tunnel being started.

Docker and Docker Compose

The official openGym quick start requires Docker with Compose. Verify both components before cloning the repository:

docker --version
docker compose version

Both commands should return version information. This guide uses the current space-separated docker compose command rather than the older standalone docker-compose form. Your user must also be permitted to communicate with the Docker daemon. If Docker returns a permission error, correct the host's Docker permissions using the supported procedure for that operating system.

Git and persistent storage

Git is needed to clone the repository:

git --version

Allow local storage for the repository, images, application data, exports, and backups. A universal minimum disk size is not established by the supplied project evidence because actual use depends on retained data and media. The exercise animations are included in the images, so the documented quick start does not require a separate animation download.

A Localtonet account and reachable client device

Install the Localtonet client on the Docker host or on another trusted device that can reach the openGym host over the local network. The selected device token identifies that client and must be kept secret. Relay server and region choices must come from the current dashboard because availability can vary.

A plan for the public hostname

Decide whether you already know the final hostname. Localtonet HTTP tunnels can use Random Sub Domain, Custom Sub Domain, or Custom Domain process types. These process types serve the same local content at a public HTTPS address, but their setup order differs for passkey-enabled applications.

  • Known hostname: If a supported custom subdomain or custom domain is already known, you can map it to RP_ID and ORIGIN before the final public test.
  • Assigned hostname: If Random Sub Domain must generate the address, create the tunnel first to discover the assigned URL. Then configure openGym, recreate its services, and perform final passkey registration through that URL.

Use only process types available in your current account and dashboard. For a custom domain, check the current Localtonet documentation before changing DNS. Do not copy DNS targets or server codes from an old tutorial.

Do not publish an uninitialized instance casually

Verify openGym locally and establish its intended profile controls before sharing the public address. A public URL makes the web endpoint reachable, but it does not replace application authentication, authorization, host maintenance, backups, or least-privilege operating practices.

Install openGym with the documented Docker quick start

Run the following commands on the machine that will host openGym. The numbered sequence preserves the current quick start shown by the project's repository. Configuration review is explained after the sequence so that it does not alter the documented installation order.

1

Clone the openGym repository

Download the official repository containing the Compose file and example environment configuration.

git clone https://github.com/DuarteSantos8/openGym
2

Enter the repository directory

Run subsequent commands from this directory so Compose can locate the project files.

cd openGym
3

Copy the example environment file

Create the private local environment file from the version supplied by the repository.

cp .env.example .env
4

Pull the published images

Pull the prebuilt amd64 or arm64 images referenced by the current Compose configuration. The project notes that skipping this command causes a source build instead.

docker compose pull
5

Start the stack

Start the configured services in detached mode.

docker compose up -d

You can compare the files used by this deployment with the current openGym example environment file and openGym Docker Compose file. Use the files from the same checked-out revision when deploying a release. Do not paste your completed .env into public issues, screenshots, or support messages.

Review configuration without changing the quick-start sequence

After the initial startup, inspect the copied .env. The documented default web port is WEB_PORT=8080. Keep it for the first local test unless port 8080 is already occupied. The current example configuration also contains the passkey-related RP_ID and ORIGIN variables. Their public values should be set only after you know the final hostname that remote browsers will use.

The project publishes its API and web images from the same release tag to GitHub Container Registry and documents a GitLab registry alternative. The normal quick start does not require changing image references.

Confirm that the containers started

docker compose ps

Look for services that remain running rather than repeatedly restarting or exiting. Service names come from the current Compose file, so they are not hardcoded here. If a service fails, inspect the project logs:

docker compose logs

Follow new log entries while reproducing a problem with:

docker compose logs -f

Press Ctrl+C to stop following logs. This does not stop containers started in detached mode.

Verify openGym locally before remote access

Open a browser on the Docker host and visit:

http://localhost:8080

With the documented default configuration, openGym should load. Select Create profile to begin the local application flow. This check proves that the containers started, the web service was published on the host, and the host browser can reach it.

A running container is not a complete application test. The container may be active while the page remains unavailable because of a startup error, dependency failure, or port conflict. Likewise, a Localtonet tunnel cannot repair an endpoint that already fails locally.

Test from the Localtonet client device when it is a separate machine

If our client will run on another device, test openGym from that device using the Docker host's LAN address and web port. Obtain the actual LAN address from the host or your network rather than guessing it. For example, the target has the shape http://LAN-ADDRESS:8080, but you must replace LAN-ADDRESS with the verified address.

If openGym works on the Docker host but not on the client device, investigate the host firewall, Docker's published-port binding, Wi-Fi client isolation, VLAN rules, and the selected host address. Do not solve this by creating a router port-forwarding rule. The Localtonet workflow uses an outbound connection instead.

Record the effective local target

If you changed WEB_PORT, use that port for local verification and for the Localtonet target. Record the exact IP address and port that work from the client device. If openGym and our client run on the same machine, the verified target is normally localhost on port 8080. If they run on different devices, use the Docker host's reachable LAN address.

Keep the local and public tests separate

Local verification confirms Docker and application availability. Public verification confirms the client, relay, tunnel target, hostname, and HTTPS route. Passkey verification adds another layer involving the exact origin, RP ID, browser, authenticator, and openGym's server-side checks.

Map the final hostname to RP_ID and ORIGIN

Diagram linking the browser hostname to openGym RP_ID and ORIGIN through a Localtonet tunnel.
Passkeys require the browser hostname, RP_ID, and HTTPS ORIGIN to describe the same public site.
The openGym relying-party ID and browser origin are derived from the final public hostname used in the browser.
The hostname portion is used for the RP ID, while the full browser origin includes the HTTPS scheme.

Passkeys use WebAuthn's domain-bound security model. A credential is registered for a relying party, and the application validates the browser origin involved in registration and authentication. This is an anti-phishing boundary. It is also why a passkey configured for one hostname should not be expected to work from an unrelated hostname.

openGym's current example environment file exposes two relevant settings: RP_ID and ORIGIN. They are related, but they are not interchangeable.

Setting Required value shape Must not contain
RP_ID A domain identifier such as gym.example.com A scheme, port, path, query string, or fragment
ORIGIN The exact browser origin such as https://gym.example.com A path, query string, or fragment
WEB_PORT The host port that publishes openGym, 8080 by default A hostname or URL

RP_ID is a domain identifier, not a URL

Set RP_ID to the hostname portion of the final public address. It has no https:// prefix, no port, and no trailing path. If the illustrative final browser URL were https://gym.example.com, the mapping would be:

RP_ID=gym.example.com

The name gym.example.com is only a reserved illustrative domain. Replace it with the exact hostname shown in your own final Localtonet URL. Do not copy the example literally, and do not guess what hostname Localtonet will assign.

ORIGIN is the exact browser origin

Set ORIGIN to the scheme and hostname that appear in the browser. Include a non-default port if the public browser URL actually uses one. A path is never part of an origin.

For the same illustrative address, the mapping would be:

ORIGIN=https://gym.example.com

If a public URL genuinely used a non-default port, its origin would include that port, such as https://gym.example.com:8443. A normal HTTPS address using the default port does not need :443. Local port 8080 does not belong in ORIGIN merely because Docker publishes openGym there. The browser sees the public HTTPS origin, not the private tunnel target.

Derive both values safely from the final URL

Suppose the dashboard shows your actual final address in this shape:

https://YOUR-FINAL-PUBLIC-HOSTNAME

Configure the variables using this direct mapping:

RP_ID=YOUR-FINAL-PUBLIC-HOSTNAME
ORIGIN=https://YOUR-FINAL-PUBLIC-HOSTNAME

Replace the placeholder with the real hostname. Do not include angle brackets or placeholder text in .env. Preserve the exact variable syntax in the current openGym .env.example from the revision you deployed.

Origin matching is exact

RP_ID must not be written as a URL. ORIGIN must include the public scheme and any non-default public port. Neither value includes an application path. A page can load successfully even when these values are wrong, so loading the interface does not prove that passkeys are configured correctly.

Apply environment changes to the containers

After saving the final values in .env, recreate the Compose services so that the containers receive them:

docker compose up -d

Confirm the resulting state and inspect logs:

docker compose ps
docker compose logs

Register passkeys only from the final public HTTPS origin that you intend to keep. A credential registered under localhost or an earlier public hostname should not be assumed to work after the relying-party identity changes.

Create the Localtonet HTTP tunnel

Start this phase only after openGym works through the local target. The HTTP tunnel forwards public browser requests to that target. It does not install openGym, start Docker, rewrite .env, or supply application authorization.

1

Install and run the Localtonet client

Run our client on the Docker host or another device that can reach the verified openGym address. It must remain connected whenever the tunnel is needed.

2

Authenticate or select the client device

Use the device-specific authentication token for the client that will run the tunnel. Keep the token secret and redact it from screenshots or support material.

3

Select an available relay server

Choose a currently available relay server or region from the dashboard. Obtain current choices from the product rather than copying an old server code.

4

Create an HTTP tunnel to openGym

Choose the HTTP tunnel family and the appropriate process type. Enter the IP address and port that succeeded during local verification. Use port 8080 unless you changed WEB_PORT.

5

Start the tunnel

Creating a tunnel does not start it. Use the Start button and confirm that the selected client and tunnel are connected. The public endpoint is available only while both remain operational.

6

Use the assigned public URL

Record the exact HTTPS address. Whether you can test passkeys immediately or must first update openGym depends on whether this hostname was known before the tunnel was created.

See the Localtonet HTTP tunnel documentation for the current dashboard workflow. Recheck the live interface before publication or support use because fields and available process types can change. Any setup screenshot must be current and must redact device tokens, private endpoints, and account details.

Choose the correct local target

When openGym and our client run on the same host, use the local address and port that passed the host test. When the client runs on a different device, localhost refers to that client device, not the Docker host. Use the Docker host's verified LAN address instead.

Avoid targeting a temporary Docker-internal container address. Container addresses can change when services are recreated. The host-published web port provides the stable boundary intended by this deployment.

Finalize the correct hostname workflow

Passkey setup must happen after the final hostname is known. The following two workflows resolve the ordering difference between known custom hostnames and newly assigned random subdomains.

Workflow A: the final hostname is already known

  1. Install openGym using the documented quick-start sequence.
  2. Verify the local endpoint at http://localhost:8080 or your deliberately configured port.
  3. Confirm that the chosen custom subdomain or custom domain is available in the current Localtonet workflow.
  4. Set RP_ID to the hostname only.
  5. Set ORIGIN to the exact HTTPS browser origin.
  6. Run docker compose up -d to apply the environment values.
  7. Create and start the HTTP tunnel for that hostname.
  8. Open the final HTTPS URL from a separate device and test openGym authentication.
  9. Register a passkey from that final origin, then sign out and test sign-in.

For a custom domain, complete only the current DNS procedure documented by Localtonet. Do not assume a DNS record type or destination from an older article.

Workflow B: Random Sub Domain assigns the hostname

  1. Install openGym using the documented quick-start sequence.
  2. Verify the local endpoint first.
  3. Create the Random Sub Domain HTTP tunnel using the verified local target.
  4. Start the tunnel so the dashboard supplies the public HTTPS URL.
  5. Copy the final hostname exactly. Do not register a passkey yet.
  6. If the instance is not ready for public use, stop the tunnel while changing application configuration.
  7. Set RP_ID to the assigned hostname without a scheme, port, or path.
  8. Set ORIGIN to the exact assigned HTTPS origin.
  9. Run docker compose up -d and inspect the resulting status and logs.
  10. Start the tunnel again, open the same HTTPS URL, and complete the passkey tests.

This order is important because the application cannot be configured for an assigned hostname before that hostname exists. Creating and briefly starting the tunnel discovers the address. Reconfiguring and recreating openGym afterward ensures that the application validates passkeys against the address users actually visit.

Perform layered final verification

Test the deployment in this order:

  1. Confirm docker compose ps shows the application services running.
  2. Load openGym through the verified local endpoint.
  3. Confirm the Localtonet client is connected and the tunnel is started.
  4. Open the public HTTPS URL from a separate browser or device.
  5. Confirm that openGym's normal profile controls appear and behave as expected.
  6. Register a passkey from the final public origin.
  7. Sign out, return to the same hostname, and authenticate with that passkey.
  8. If multiple devices are needed, use openGym's supported one-time-code or QR pairing flow rather than manually sharing credentials.

A successful page load validates reachability, not authorization. A successful passkey registration is also not enough by itself. Test a fresh authentication ceremony and verify that the resulting user reaches only the correct openGym profile.

Routine operation, updates, and recovery planning

Start and inspect openGym

From the repository directory, start or recreate the configured stack with:

docker compose up -d

Inspect it with:

docker compose ps

After a host reboot, check Docker, the Compose services, the Localtonet client, and the tunnel separately. A connected tunnel cannot serve stopped containers, and a healthy local application is not public while the client or tunnel is offline.

Stop the Compose stack carefully

docker compose down

This stops and removes the running containers and Compose network. Do not add volume-removal options unless you have verified exactly what data they would delete. The precise persistent-storage definitions can change, so inspect the Compose file from the deployed revision before performing destructive maintenance.

Update conservatively

Read release notes and create a verified backup before updating. Container releases can introduce environment changes or data migrations. A typical image refresh uses:

docker compose pull
docker compose up -d

These commands do not replace release-specific instructions. If repository files changed, review the differences in .env.example and docker-compose.yml. Merge required settings into your private .env without overwriting secrets or deliberate hostname values.

Back up application data and configuration

openGym provides JSON export, which gives you a portable copy of application data. Keep regular exports away from the server. Also back up the persistent locations defined by the exact Compose deployment you use.

This guide does not invent a universal host path because the supplied evidence does not establish one path for every release and storage arrangement. Review named volumes and bind mounts in the current Compose file, use consistency procedures appropriate to the services, and test restoration on a separate deployment.

Control public availability independently

Stop the Localtonet tunnel when openGym should remain local. You do not need to stop Docker. Conversely, stopping the containers leaves the tunnel configuration present but removes its working target. Delete the tunnel when it is no longer needed.

Security checklist for public openGym access

Self-hosting gives you operational control and responsibility. Workout history, body weight, profile information, and progress photos can be sensitive. Protect the service as a private application even when it is used only by a small number of people.

๐Ÿ”‘ Protect each identity layer Keep Localtonet device tokens secret, use openGym authentication, and secure host and Docker administration separately.
๐ŸŒ Expose only the web port Point one HTTP tunnel at openGym's published web service. Do not expose Docker sockets, databases, shells, or unrelated host services.
๐Ÿ”’ Separate transport from authorization HTTPS protects traffic to the public endpoint. openGym must still determine who may authenticate and access each profile.
๐Ÿงฉ Keep software current Review openGym releases, container updates, Docker, the host operating system, browsers, and the Localtonet client.
๐Ÿ’พ Maintain tested backups Combine JSON exports with persistent-storage backups and periodically verify that restoration works.
๐Ÿ›‘ Limit unnecessary exposure Stop the tunnel during initialization, maintenance, authentication changes, or periods when remote access is not required.

Do not commit provider credentials, Localtonet tokens, or private environment values to the repository. openGym's optional AI coach uses user-supplied provider configuration and is off by default. Review what an optional integration can access and how its credentials are stored before enabling it on a public instance.

Keep the public hostname deliberate and stable. Changing it can invalidate the assumptions behind existing passkeys and cause users to create duplicate credentials. Confirm that a replacement authentication path works before deleting the only credential associated with an older hostname.

A public HTTPS URL is not an authorization policy

HTTPS protects data in transit between the browser and public endpoint. The tunnel provides network reachability. Neither one decides which person may access a profile. Keep openGym's authentication and authorization correctly configured, and never treat an obscure URL as the sole control protecting personal data.

Troubleshooting openGym, passkeys, and the tunnel

A five-stage troubleshooting flow checks Docker, local access, domain matching, the tunnel, and remote access.
Test from the application outward so that container, local-network, hostname, WebAuthn, and tunnel failures remain distinguishable.

Docker Compose cannot find the project configuration

Confirm that your shell is inside the cloned openGym directory. Verify that docker-compose.yml and .env.example exist. If cloning was interrupted, preserve any work you need before replacing the incomplete directory.

The docker compose command is unavailable

A working Docker engine does not guarantee that the Compose plugin is installed. Run docker compose version, then install or enable the current plugin using the supported method for your operating system.

Port 8080 is already in use

Identify the process using the port and decide whether to stop it or change openGym's WEB_PORT. After changing the port, run docker compose up -d, verify the new local endpoint, and update the Localtonet target. The public ORIGIN still describes the browser-visible HTTPS address, not the local port.

Containers exit or restart repeatedly

Run docker compose ps and docker compose logs. Check for invalid environment values, failed image pulls, unavailable dependencies, file-permission errors, or resource exhaustion. Return to the copied example configuration rather than making several speculative changes at once.

openGym works on its host but not from the Localtonet client device

Test the Docker host's LAN address and web port from the client device. Confirm that the network permits peer communication and that the host firewall allows the intended LAN connection. Remember that localhost always means the machine making the connection.

The public URL does not load

  1. Confirm openGym still loads from the exact local target.
  2. Confirm the Compose services are running.
  3. Confirm the Localtonet client is connected.
  4. Confirm the correct device is associated with the tunnel.
  5. Confirm the tunnel was started rather than only created.
  6. Confirm its local IP address and port match the tested endpoint.

If a previously working tunnel stops, check whether the host slept, the client exited, Docker stopped, the local address changed, or the tunnel was manually stopped.

The page loads, but passkey registration fails

Reachability is working, so focus on the WebAuthn and application layer. Confirm that the browser uses the intended HTTPS hostname. Verify that RP_ID contains only that hostname and that ORIGIN contains the exact HTTPS origin. Recreate the Compose services after modifying .env, then inspect logs.

Also verify browser and device support. Platform authentication, browser privacy settings, credential synchronization, and external authenticator behavior vary by device. These capabilities are independent of the tunnel.

RP_ID contains https:// or a port

Remove them. RP_ID is not a URL. For a browser origin such as https://gym.example.com, the RP ID is gym.example.com. A scheme, port, path, query, or fragment makes the value the wrong shape.

ORIGIN contains a path

Remove the path. For a page such as https://gym.example.com/profile/login, the origin is https://gym.example.com. The path identifies a resource within the origin and is not part of WebAuthn's origin value.

A passkey stopped working after the hostname changed

The credential may be scoped to the previous relying-party identity. Correct the environment for the final hostname and use openGym's supported profile or device-pairing workflow to establish access from the new origin. Do not delete the only working access method until the replacement has been tested.

The application appears stale after an update

Confirm which images are running, recreate the services, and try a private browser window to rule out cached frontend resources. Compare the current example environment file with your private file, preserving credentials and the final passkey hostname while adding required new settings.

Workout data appears missing

Stop making destructive changes. Verify that you opened the intended instance and profile, that the expected persistent storage is mounted, and that the update did not start a fresh Compose project from another directory. Inspect volume and bind-mount definitions before removing anything. Restore only after understanding the cause and validating the backup.

Frequently asked questions

What port does openGym use by default?

The documented default is WEB_PORT=8080, with a local quick-start endpoint of http://localhost:8080. If you change it, use the new port for local verification and the Localtonet target.

What exactly belongs in RP_ID?

RP_ID contains the final public hostname only. It does not include https://, a port, a path, a query, or a fragment. If the illustrative browser origin is https://gym.example.com, the RP ID is gym.example.com.

What exactly belongs in ORIGIN?

ORIGIN contains the exact browser-visible scheme and hostname, plus any non-default public port. It does not include a path, query, or fragment. A typical value has the shape https://gym.example.com.

Why is local port 8080 not included in the public ORIGIN?

Port 8080 belongs to the private target used by Docker and the tunnel. ORIGIN describes what the browser sees. If the browser opens a normal HTTPS URL without an explicit non-default port, port 8080 does not appear in the origin.

Can I use a Random Sub Domain with passkeys?

Yes, provided that you first create the tunnel to discover its assigned URL, configure openGym's RP_ID and ORIGIN for that exact hostname, recreate the services, and then register and test passkeys from the final HTTPS origin.

Can I test openGym before configuring a public domain?

Yes. Verify the application locally at http://localhost:8080. Public passkey testing is a later phase that requires the final HTTPS hostname and matching application settings.

Do I need to forward port 8080 on my router?

No. The Localtonet client establishes an outbound connection to our relay. This workflow does not require inbound router port forwarding, a public IP address, firewall changes for inbound internet traffic, or VPN setup.

Does HTTPS mean that anyone with the URL is authorized?

No. HTTPS protects transport between the browser and endpoint. It does not grant or deny profile access. openGym must continue to authenticate users and enforce authorization.

Does creating a Localtonet tunnel start it automatically?

No. Creating the tunnel saves its configuration. You must use the Start button, and the selected client must remain connected. You can stop or delete the tunnel independently of the openGym containers.

Can the Localtonet client run on another device?

Yes, if that device can reach the Docker host's LAN address and web port. In that arrangement, do not target localhost, because it would refer to the client device rather than the openGym host.

Is the public URL available when the host is turned off?

No. Remote access depends on the host, openGym containers, Localtonet client, and tunnel all being operational. The tunnel is available only while the selected client is connected and the tunnel is running.

Connect your verified openGym instance with Localtonet

Install openGym, verify its local web service, obtain or confirm the final public hostname, map that hostname precisely to RP_ID and ORIGIN, and then test the complete HTTPS and passkey flow without opening an inbound router port.

Get Started Free โ†’

Corrections & updates

Substantive changes approved by the Localtonet editorial team are listed transparently below.

Remove the outer article wrapper; move the hero to the beginning and keep the clickable guide card directly after it; verify the current openGym .env.example and document the exact RP_ID and ORIGIN value formats; reorganize the hostname, tunnel, application restart, and passkey-registration sequence so it works for both known custom hostnames and newly assigned subdomains; preserve openGym's documented Docker quick-start sequence exactly; add contextual links to the openGym repository and current configuration files; clarify that RP_I

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support