Run a persistent database workspace locally, then give it controlled HTTPS access
WhoDB provides a browser-based workspace for connecting to databases, inspecting data, and working with database structures. In this guide, we install WhoDB with Docker Compose, preserve encrypted login sessions, and verify database connectivity from inside Docker. We bind the web interface to the host’s loopback address before connecting it to a Localtonet HTTP tunnel. You will also learn how to choose a reproducible image version, handle secure cookies, verify the remote path, and maintain the deployment.
📋 What's in this guide
How the WhoDB and Localtonet architecture works
The deployment has three separate network paths. A browser reaches WhoDB through the tunnel’s public HTTPS address. The Localtonet client forwards requests to WhoDB’s published HTTP port on the Docker host. WhoDB then connects to databases from inside its container. A working browser interface does not prove that the database path works, and a healthy database does not prove that the tunnel is running.
WhoDB’s default internal HTTP listener is port 8080. This guide publishes it using 127.0.0.1:8080:8080, making the host-side endpoint http://127.0.0.1:8080. Our client runs directly on that same host and targets 127.0.0.1, port 8080. A client running in a separate container has its own loopback namespace and is not the same arrangement.
The Localtonet client establishes an outbound connection to a relay server. Our platform provides the public address without requiring inbound router port forwarding, a public IP address, inbound firewall changes, or VPN setup. That does not change Docker’s own publication behavior: a mapping such as 8080:8080 normally publishes on all host interfaces and can expose WhoDB to reachable networks independently of the tunnel.
Use a current Docker release and review Docker’s port-publishing documentation for platform-specific behavior. Loopback publication reduces direct network exposure; it is not application authorization or isolation from other software and users on the host.
clidey/whodb image runs the interface and backend, with an internal HTTP listener on port 8080 by default.
/data retains the encrypted session database. A stable encryption key lets replacement containers decrypt it.
HTTPS protects the browser connection in transit. It does not decide who may use WhoDB, authorize database operations, or make a public URL private. Do not rely on an obscure address as an access control. Before publication, establish an authentication and access-control policy appropriate to your deployment, use least-privilege database accounts, and avoid exposing managed profiles that grant unintended access. If you cannot meet that policy, keep the interface private rather than starting a public tunnel.
Prepare the host and choose the publication address
This tutorial covers the published Docker image, not a source build or desktop installation. WhoDB also supports a standalone binary, desktop application, and source checkout, as described in its official installation guide. Docker Compose is useful here because it records the image, port binding, environment, volume, and restart policy together.
- Install Docker and the Docker Compose plugin for your operating system.
- Have permission to manage containers, images, volumes, and deployment files.
- Choose an unused host port, normally 8080.
- Have a reachable database and a dedicated, appropriately limited database account.
- Have OpenSSL available for generating the session-encryption key.
- Install the Localtonet client directly on the Docker host for the recommended workflow.
- Keep your device-specific Localtonet authentication token private and separate from WhoDB configuration.
docker --version
docker compose version
openssl version
If Docker or Compose is unavailable, complete the supported installation for your host first. Docker’s Compose documentation explains installation and the Compose file model. The shell examples below use a POSIX-style terminal; adapt line continuations for another shell, or enter commands on one line.
Host ports and container ports are different
In 127.0.0.1:8080:8080, the first value is the host binding address, the second is the host port, and the third is the container port. To avoid an occupied host port, change only the middle value. Changing WhoDB’s PORT variable instead changes the application’s internal listener and requires corresponding mapping and health-check changes.
| Configuration | Host URL and tunnel target | Purpose |
|---|---|---|
127.0.0.1:8080:8080 | http://127.0.0.1:8080 | Recommended same-host workflow. |
127.0.0.1:3000:8080 | http://127.0.0.1:3000 | Alternative host port; internal listener remains 8080. |
PORT=3000 with 127.0.0.1:3000:3000 | http://127.0.0.1:3000 | Intentional change to the internal listener as well. |
When the Localtonet client runs on another device
A second device cannot reach the Docker host’s loopback binding. That layout requires deliberately publishing WhoDB on a host address reachable from the client, then targeting that address and host port in Localtonet. Prefer a specific LAN interface rather than all interfaces, and restrict access according to your local network and firewall policy. Verify reachability from the actual client device before creating the tunnel.
This is a separate local-network decision, not a requirement to open an internet-facing router port for Localtonet. If you do not need cross-device connectivity, retain the loopback binding. Also remember that stopping the tunnel does not disable any LAN access you deliberately enabled.
Choose a reproducible WhoDB image
clidey/whodb:latest is convenient for a disposable evaluation, but it is a moving tag. A later pull can retrieve different software even when the Compose file has not changed. For controlled deployments, review a release and select its versioned image rather than relying on latest.
The official WhoDB 0.138.0 release lists clidey/whodb:0.138.0 and is marked as an immutable GitHub release. We use that evidenced version in the persistent examples below as a reproducibility example, not as a promise that it is the newest or appropriate release for every deployment. Check current release notes and security fixes before selecting your version.
An immutable GitHub release and an immutable container reference are not identical guarantees. Registry tags can be reassigned unless the registry enforces immutability. For strict reproducibility, pull your reviewed version, record its repository digest, and use the verified clidey/whodb@sha256:... reference in Compose. Do not paste the ellipsis literally.
docker pull clidey/whodb:0.138.0
docker image inspect clidey/whodb:0.138.0 --format '{{json .RepoDigests}}'
Pinning makes changes intentional; it does not install security updates automatically. Keep an explicit review, backup, update, and verification process. Preserve the previous image reference so you know which software was deployed before a change.
Run a quick local WhoDB container
For a temporary smoke test, the following command adapts WhoDB’s official Docker integration to a loopback-only binding. The moving latest tag is intentional for this disposable test. Do not use sensitive database credentials just to prove the page loads.
docker run -d \
--name whodb \
-p 127.0.0.1:8080:8080 \
clidey/whodb:latest
docker ps --filter name=whodb
docker logs whodb
Open http://127.0.0.1:8080 on the Docker host. If the page does not load, inspect the container state and logs before adding a tunnel. Follow new output with docker logs -f whodb; interrupting the log viewer does not stop the container.
A plain container can generate an encryption key and store sessions in its writable filesystem. Removing and replacing it loses that container-local state. Use the volume and stable key below for session continuity across recreation.
Before moving to Compose, remove the disposable container to release its name and port. This command deletes that container’s nonpersistent state:
docker rm -f whodb
Install WhoDB with persistent encrypted sessions
WhoDB stores login sessions server-side. Database credentials are encrypted with AES-256-GCM in a local SQLite file under its data directory. The browser receives an opaque HttpOnly session cookie rather than the credentials themselves. Persisting /data and setting a stable WHODB_ENCRYPTION_KEY keeps these encrypted sessions usable after container replacement, subject to normal expiration.
Generate and protect the encryption key
mkdir whodb-deployment
cd whodb-deployment
openssl rand -hex 32
The OpenSSL command produces 32 random bytes represented as 64 hexadecimal characters. Generate this value once, store it securely, and replace the placeholder in the configuration below. Do not commit the real key to source control or include it in support output.
Changing or losing the key makes existing encrypted sessions unreadable, requiring users to sign in again. Anyone who obtains both the key and session data may gain access to stored credentials. Encryption is not a substitute for protecting the host, Docker access, deployment files, and backups.
Create docker-compose.yml
services:
whodb:
image: clidey/whodb:0.138.0
container_name: whodb
ports:
- "127.0.0.1:8080:8080"
environment:
PORT: "8080"
WHODB_LOG_LEVEL: info
WHODB_ENCRYPTION_KEY: replace_with_your_64_character_hex_key
restart: unless-stopped
volumes:
- whodb-data:/data
volumes:
whodb-data:
Replace the key placeholder before startup. A value written in Compose is visible to people who can read the file, and container environment values are accessible to users with sufficient Docker permissions. Limit access using your operating system’s permissions and secret-management practices. Moving a secret into an environment file keeps it out of the main YAML but does not, by itself, make it inaccessible.
docker compose up -d
docker compose ps
docker compose logs whodb
Open http://127.0.0.1:8080. Leave WHODB_SECURE unset during this plain-HTTP test. We enable secure cookies before authenticated use through the HTTPS tunnel.
Session lifetime and optional environment settings
The default WHODB_SESSION_TTL is 168h, or seven days, using a sliding idle timeout. Persistence protects sessions from container replacement; it does not bypass expiration. Choose a session duration that fits your access policy rather than increasing it simply to avoid reauthentication.
| Variable | Documented behavior | Practical guidance |
|---|---|---|
WHODB_LOG_LEVEL | debug, info, warn, error, or none; default info. | Use verbose logging temporarily for diagnosis. |
WHODB_LOG_FORMAT | json enables JSON logs; default is text. | Useful for log-processing systems. |
WHODB_SESSION_TTL | Sliding idle timeout expressed as a Go duration. | Default is 168h. |
WHODB_SECURE | true marks the session cookie Secure. | Enable for HTTPS browser access, not plain-HTTP testing. |
WHODB_ALLOWED_ORIGINS | Comma-separated CORS allowlist. | CORS is not authentication or a general access-control boundary. |
WHODB_MAX_PAGE_SIZE | Maximum rows per page request; default 10000. | Consider the amount of data each request may return. |
WHODB_DISABLE_CREDENTIAL_FORM | Hides manual credentials and requires managed profiles or providers. | Configure and test the managed login path first. Hiding a form alone is not authorization. |
Connect WhoDB to databases from inside Docker
Choose the database hostname according to the database’s location. For a sibling service on the same Compose network, use its service name, such as postgres, and its internal database port. For a remote server, use a hostname or address routable from the container. Only a database inside the WhoDB container itself would normally be reached through that container’s localhost.
Connecting to a database on the Docker host
Docker Desktop commonly provides host.docker.internal for reaching the host. Do not assume that name exists in every Docker Engine environment. On compatible Docker Engine installations, particularly Linux hosts, add this fragment under the existing whodb service to map the name to Docker’s host gateway:
extra_hosts:
- "host.docker.internal:host-gateway"
Recreate the service with docker compose up -d after changing it. The special host-gateway value requires a supporting Docker Engine version. Rootless, remote-daemon, and customized network configurations may need a different reachable host address; verify the network route rather than copying a fixed bridge IP.
Name resolution is only the first requirement. A host database bound solely to host loopback may not accept traffic arriving through a bridge gateway. Configure the database listener, database client-access policy, and host firewall deliberately for the container source. Do not solve a connection failure by exposing the database indiscriminately. Prefer a shared private Compose network when both applications can run as containers.
Disposable PostgreSQL networking demonstration
The following fragment is an optional addition to the services section of the existing Compose file. It demonstrates service-name networking only. It does not replace the persistent WhoDB configuration:
postgres:
image: postgres:16
environment:
POSTGRES_USER: whodb_demo
POSTGRES_PASSWORD: replace_with_a_unique_demo_password
POSTGRES_DB: whodb_demo
This demonstration has no explicitly managed database data volume or backup workflow. Do not rely on its database state surviving replacement. The official PostgreSQL image initializes POSTGRES_USER as a privileged account, not a least-privilege application user. Use it only to demonstrate connectivity with synthetic data. For a real database, configure persistent storage, backups, and a separate restricted account before connecting WhoDB.
Replace the password placeholder, then start and inspect PostgreSQL:
docker compose up -d postgres
docker compose logs postgres
docker compose exec postgres pg_isready -U whodb_demo -d whodb_demo
In WhoDB, choose PostgreSQL and enter host postgres, port 5432, database whodb_demo, user whodb_demo, and the password you set. No PostgreSQL host port needs publishing because both services share the Compose network. A readiness check confirms that the server is accepting connections; a successful WhoDB login separately verifies the credentials and network path.
You may add depends_on: [postgres] to WhoDB for startup ordering, but basic depends_on does not prove database readiness. PostgreSQL may still be initializing when WhoDB starts. Inspect readiness and retry the connection, or use an appropriate database health check and Compose health-based dependency condition when designing automated startup.
For actual work, grant only the schemas, tables, and operations needed by the operator. Read-only inspection should not require a database superuser. WhoDB’s effective database capabilities depend on the permissions of the account used to connect.
Verify the application, database, and session persistence
Complete local verification before creating a tunnel. A tunnel cannot repair an exited container, incorrect Docker mapping, or unreachable database.
- Run
docker compose psand confirm WhoDB is not repeatedly exiting or restarting. - Check the host-side health endpoint and expect the plain-text body
ok. - Open the browser interface at
http://127.0.0.1:8080. - Connect with the intended database account and verify only authorized operations.
- Recreate WhoDB, keeping its volume and key, then test the existing browser session.
curl --fail --show-error http://127.0.0.1:8080/health
docker compose up -d --force-recreate whodb
Revisit the same browser origin after recreation. A session on 127.0.0.1 is not the same browser cookie context as a later public hostname. Normal idle expiration can also require reauthentication. Do not run docker compose down -v for this test: -v removes the named volume needed for continuity.
Add an internal Docker health check
Add this fragment under the existing whodb service:
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/health | grep -qx ok"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Apply it with docker compose up -d. This follows the documented WhoDB health-check approach and executes inside the container. It therefore uses the internal listener port, even if the host port is 3000. Verify that the selected image includes the commands used by the probe.
An internal health check does not test the host publication, a database query, or the tunnel. An unhealthy status also does not by itself make the Docker restart policy restart a running process. Continue testing each layer separately.
Add Localtonet HTTPS access
Once the local service works, use an HTTP tunnel for WhoDB’s browser-based interface. For this same-host deployment, the local target is 127.0.0.1 and port 8080. If you selected host port 3000, use port 3000 in the tunnel, not the container’s internal 8080.
Prepare secure cookies before remote login
WhoDB does not infer the original HTTPS scheme from proxy headers. Add WHODB_SECURE: "true" under its existing environment mapping before using the public HTTPS address for authenticated access:
environment:
PORT: "8080"
WHODB_LOG_LEVEL: info
WHODB_ENCRYPTION_KEY: replace_with_your_64_character_hex_key
WHODB_SECURE: "true"
Retain your actual existing key; do not generate a new one for this change. Keep the reviewed image, loopback port binding, volume, and other settings unchanged.
docker compose up -d
curl --fail --show-error http://127.0.0.1:8080/health
The health endpoint remains usable over local HTTP because it does not require an authenticated browser session. Secure cookies are intended for HTTPS; do not rely on local HTTP login behavior after enabling this setting.
Create and start the HTTP tunnel
Use the current Localtonet HTTP tunnel documentation alongside the workflow below. Client installation details vary by operating system and version; obtain the current installer and device token through our official product pages rather than using an invented CLI command.
Install and run our client
Run the Localtonet client directly on the Docker host so it can reach the loopback-published WhoDB service.
Authenticate the device
Use its device-specific authentication token. Keep that token out of Compose files, screenshots, repositories, and shared logs.
Select an available relay server
Choose a currently available server or region from the dashboard. Do not copy an assumed server code from another deployment.
Configure an HTTP tunnel
Set the local IP to 127.0.0.1 and port to 8080, or your selected host port. Choose the appropriate Process Type: Random Sub Domain, Custom Sub Domain, or Custom Domain, according to current availability.
Start the tunnel
Use Start. Creating or saving a configuration does not make it run. Both the selected client connection and the tunnel must be active.
Verify the public HTTPS address
Open the assigned address and test the intended login and permitted database operations. Stop or delete the tunnel when remote access is no longer needed.
Custom-domain DNS requirements must be checked against current documentation before changing records. Options and availability can vary by plan or deployment. This HTTP workflow exposes WhoDB, not a raw database port, and is not a VPN.
Verify the complete remote path
Test from a different device or network when possible. Confirm the URL uses HTTPS, the interface renders, login persists after refresh, and the account cannot perform operations outside its intended permissions. You will normally sign in again on the public hostname because its browser cookie context differs from the local address.
Inspect browser cookie and network diagnostics without copying cookie values into support tickets. Test the access restrictions you actually configured, including rejection of unauthorized users where applicable. Successful access by an authorized user alone does not prove that restrictions are effective.
Finally, stop the tunnel and confirm the public path becomes unavailable while the local health check still succeeds. This verifies that you can withdraw remote access independently. It does not revoke existing credentials or disable other network paths you may have published.
Operate, update, back up, and troubleshoot WhoDB
Routine operation
docker compose ps
docker compose logs -f whodb
docker compose restart whodb
docker compose stop whodb
docker compose start whodb
A restart retains the container’s current configuration. After changing environment variables, image references, or port mappings, use docker compose up -d to apply the configuration through recreation where needed. The unless-stopped restart policy does not manage the Localtonet client or tunnel. Verify both layers after reboot, and account for host sleep or network loss.
An explicit update process
- Review the intended WhoDB release, compatibility notes, and security fixes.
- Record the current image reference and back up the session data, key, and deployment configuration.
- Change the Compose image to the newly reviewed version or verified digest.
- Pull and recreate WhoDB, preferably during a maintenance window.
- Repeat local health, browser, database, session-persistence, and remote-path checks.
docker compose pull whodb
docker compose up -d whodb
curl --fail --show-error http://127.0.0.1:8080/health
docker compose logs whodb
With a pinned image, pulling does not select a newer version automatically. With latest, pulling can change what the tag resolves to. Neither choice updates a running container merely because a release exists. Keep a rollback plan, but do not assume an older image can safely read data modified by a newer version; review migration behavior and retain a restorable backup.
Backups and logs
Back up the /data volume and stable encryption key through protected processes. Use a consistent volume snapshot or stop WhoDB during a filesystem backup of its SQLite data. Preserve the deployment configuration and image reference, and test restoration in an isolated environment before depending on it. Compose project naming can affect which named volume is selected, so preserve or deliberately map the correct volume when moving the deployment.
The WhoDB session volume is not a backup of connected databases. Each database needs its own persistence, backup, recovery, and access policy. Avoid casually running docker compose down -v or volume-pruning commands against a deployment you intend to retain.
Standard logs are available through Docker. WhoDB also supports WHODB_LOG_FILE, WHODB_ACCESS_LOG_FILE, and WHODB_AUDIT_LOG_FILE. Setting them to default uses files under /var/log/whodb/; the audit log is append-only NDJSON for audited actions such as logins, reads, and changes. Mount an appropriate path if file logs must survive recreation, and plan permissions and retention.
Inspect logs before sharing them. Hostnames, database names, usernames, query content, and other operational data may be sensitive. Do not expose encryption keys, device tokens, database passwords, or session cookies during troubleshooting.
Port conflicts and binding mistakes
If WhoDB cannot start, inspect logs for an occupied port, invalid YAML, an invalid key, or a conflicting container named whodb from the quick test. To change only the host port, use:
ports:
- "127.0.0.1:3000:8080"
Then use http://127.0.0.1:3000, http://127.0.0.1:3000/health, and tunnel target port 3000. The internal Docker health probe still uses 8080. Inspect the published mapping in docker compose ps; a displayed all-interface binding is not the intended same-host configuration.
Database and hostname failures
If the page works but database login fails, check the hostname from the container’s perspective, the database listener and port, credentials, permissions, and network policy. If host.docker.internal does not resolve, review platform support and the extra_hosts mapping. If it resolves but the connection fails, investigate the route and database listener rather than repeatedly changing passwords. A newly started PostgreSQL container may simply not be ready yet.
Session resets and login loops
If sessions disappear after recreation, confirm that the same volume is mounted at /data and the encryption key has not changed. Check expiration and whether you switched browser hostnames. If the key is lost, old sessions cannot be decrypted and users must sign in again. If login fails after enabling secure cookies, verify that authenticated access uses HTTPS and that the changed environment was applied with Compose.
Public-path failures
If local access works but public access does not, check the Localtonet device connection, tunnel running state, target address, and host port. A client on another device cannot use this host’s loopback endpoint. Either move the client to the Docker host or intentionally configure a restricted, reachable LAN publication. A sleeping device, stopped client, or stopped tunnel interrupts public availability even if WhoDB is configured correctly.
| Symptom | First check | Likely area |
|---|---|---|
| Local and public URLs both fail | Container state, logs, host health request | Application listener or Docker publication |
| Internal health succeeds, host request fails | Published address and host port | Port mapping or wrong network namespace |
| Local works, public fails | Client, tunnel, target IP and port | Tunnel lifecycle or target reachability |
| Page works, database fails | Database hostname, readiness, and account | Database network path or permissions |
| Sessions reset after recreation | Volume, key, hostname, idle lifetime | Persistence or cookie context |
| Public HTTPS login loops | Applied secure-cookie setting and browser diagnostics | Cookie policy or session configuration |
Frequently asked questions
Why use 127.0.0.1:8080:8080 instead of 8080:8080?
The explicit loopback binding limits the host-published interface to local access in the recommended same-host layout. A mapping without a host address normally publishes on all interfaces, potentially making WhoDB reachable independently of Localtonet.
Does Localtonet require router port forwarding or firewall changes?
Our client establishes an outbound relay connection, so the tunnel does not require inbound router port forwarding or inbound firewall changes. Docker publication is separate. A client on another device needs deliberately permitted local-network access to the WhoDB host.
Why do persistent sessions need a volume and a stable key?
The volume retains encrypted session data under /data. The stable WHODB_ENCRYPTION_KEY lets replacement containers decrypt it. Losing either prevents existing sessions from continuing normally, and persistence does not override session expiration.
When should WHODB_SECURE be enabled?
Leave it unset for initial plain-HTTP testing. Set it to true before authenticated use through the public HTTPS address, then recreate the service and verify login. The local health endpoint can still be checked over HTTP.
Does host.docker.internal work everywhere?
No. Docker Desktop commonly supplies it, while compatible Docker Engine environments may need an explicit host-gateway mapping. Name resolution alone does not ensure that a host database listens on an address reachable from the container.
Does the tunnel expose PostgreSQL or other database ports?
Not in this workflow. The HTTP tunnel targets WhoDB’s web interface. WhoDB reaches databases through its own network path. That interface still provides sensitive database capabilities, so not publishing a raw database port does not remove the need for authorization.
Will everything return automatically after reboot?
WhoDB uses restart: unless-stopped, but Docker must be running. Remote access separately requires the Localtonet client to reconnect and the tunnel to be running. Verify the application, database, and tunnel after reboot.
Can I stop public access without stopping WhoDB?
Yes. Stop the Localtonet tunnel while leaving WhoDB running locally. Any separately configured LAN publication remains independent, so retain the loopback-only binding unless another device genuinely needs direct access.
Give your verified WhoDB deployment HTTPS access
Start with a healthy loopback-bound container, protected session storage, and least-privilege database credentials. Then use a Localtonet HTTP tunnel for the remote-access window you actually need, without configuring inbound router port forwarding.
Get Started Free →