Run your engineering wiki locally, verify its access controls, and connect remote teammates
Oxynote combines engineering documentation, diagrams, collaborative editing, reviewable changes, and live metric charts. This guide runs its documented container image with persistent storage and a security-conscious loopback port binding, then verifies the application before adding remote access. We also install our Localtonet client as a Linux service and explain how an HTTP tunnel reaches the working wiki. Where the available project evidence does not establish a credential, configuration detail, or migration procedure, we identify the limitation instead of guessing.
๐ What's in this guide
How this deployment works
Oxynote is an open-source workspace for the systems an engineering team operates. Architecture notes, API references, on-call procedures, release checklists, diagrams, and code can share a searchable page tree. Its editor supports collaborative editing and comments, while reviewable pages use drafts, block-aware diffs, approval, and a separate merge action.
The installation covered here uses one Docker container and a named volume, oxynote_data, mounted at /oxynote/data. Oxynote listens on container port 8080. For our recommended layout, Docker publishes that port only on the host's IPv4 loopback address, and the Localtonet client runs directly on that same host.
Our client establishes an outbound connection to a Localtonet relay. A running HTTP tunnel provides a public HTTPS address and forwards requests to the configured local HTTP target. This publishing path needs no inbound router port forwarding or public IP address. It is not a VPN, and it does not replace Oxynote authentication or application permissions.
Loopback and LAN access are different deployment choices
Oxynote's published quick-start command uses -p 8080:8080. With normal Docker defaults, omitting the host IP publishes the port on all host interfaces, not just localhost. The actual reachability depends on routing, host access controls, and Docker networking, but opening the application at localhost does not make that deployment local-only.
For a same-host client, use -p 127.0.0.1:8080:8080. This explicitly selects the host's IPv4 loopback interface. Use an up-to-date Docker installation and verify the effective mapping and network behavior rather than treating a command alone as a complete security assessment.
If our client runs on another device, it cannot reach this loopback binding over the LAN. That topology needs a deliberately selected private host address, an appropriate Docker publication or approved internal proxy, and host access controls permitting only the intended client. A private address is not an authentication mechanism, and the HTTP hop across that network is separate from the public HTTPS connection.
Prerequisites and deployment decisions
The concrete Localtonet installation below uses the Debian/Ubuntu x64 package on the Docker host. Our Linux packages require systemd 247 or newer and OpenSSL 3; Debian 12 and compatible Ubuntu 22.04+ installations are examples. Docker must already be installed and operational. Other supported client builds exist, but their installation commands differ.
- Use an authorized host and an account permitted to manage Docker and install the Localtonet package.
- Ensure the host can retrieve the Oxynote image from GitHub Container Registry and make the required outbound Localtonet connection.
- Reserve host TCP port
8080and enough disk space for documentation, attachments, and backups. - Have local browser access or an approved administrative access path for initial setup.
- Have a Localtonet account and the device-specific AuthToken for this client.
- Decide who owns backups, updates, account administration, and access reviews before storing important documentation.
The available Oxynote evidence does not specify authoritative CPU, RAM, disk, Docker-version, or operating-system minimums. Monitor actual resource use rather than relying on invented sizing figures. Its single-container command also does not establish a production external-database configuration, a Compose deployment, or an application-consistent backup procedure.
Check Docker before installing the application
docker info
docker ps
The first command should reach the Docker daemon. Resolve missing-command, daemon-connection, and permission errors first. The second shows running containers and their published ports. Look for an existing mapping using 8080; non-Docker processes can also occupy that port, so use your host's networking tools if startup reports a conflict.
These commands assume Docker runs on the machine you intend to use. If your Docker CLI targets a remote daemon, its published ports and volumes belong to that remote host, not necessarily to the computer running your terminal.
Understand the persistence boundary
The named volume survives an ordinary container stop and has its own lifecycle. It is not a backup. Disk failure, accidental deletion, or a failed application migration can still destroy data. Before production use, establish and test a backup and restore process appropriate to the deployed Oxynote version. Copying live application files without understanding consistency requirements is not automatically a reliable backup.
Install Oxynote with a loopback-bound Docker port
The Oxynote project website supplies this quick-start command. It is reproduced for comparison, not as the recommended initial binding for this guide:
docker run -d -p 8080:8080 -v oxynote_data:/oxynote/data ghcr.io/oxynote/oxynote
-p 8080:8080 normally publishes on all host interfaces. Do not run it on the assumption that initial setup is isolated from the LAN or other reachable networks. For our same-host Localtonet layout, use the loopback-bound variation below instead. Run one installation command, not both.
Start the same-host deployment
Run the following on the Docker host. The only change from the project's command is the explicit host binding:
docker run -d -p 127.0.0.1:8080:8080 -v oxynote_data:/oxynote/data ghcr.io/oxynote/oxynote
Docker retrieves the image if necessary, creates or reuses the named volume, starts the container in detached mode, and returns a container identifier. Save that identifier. Because the command does not assign a name, Docker also generates one. Use the existing identifier for later maintenance rather than repeatedly creating containers.
| Argument | Purpose | Implication |
|---|---|---|
docker run | Create and start a container. | Running it again creates another container. |
-d | Run in the background. | Use logs and status commands to inspect startup. |
-p 127.0.0.1:8080:8080 | Map host loopback port 8080 to container port 8080. | A same-host client can target 127.0.0.1:8080. |
-v oxynote_data:/oxynote/data | Attach the documented persistent data volume. | Protect this volume independently of the container. |
ghcr.io/oxynote/oxynote | Select the upstream image reference. | No explicit version tag or digest is pinned. |
Do not mistake the image reference for a version pin
An image reference without a tag uses Docker's default latest tag. Tags are mutable, so this command is not a reproducible release pin. A previously cached image may differ from an image fetched later under the same reference. The project material mentions release v0.9.3, but that does not prove that this untagged image resolves to that release or that a corresponding container tag exists.
Record the actual image used by your container. If reproducibility is required, validate an appropriate published image digest or immutable release reference before standardizing it. Do not invent a version tag based only on a GitHub release name.
If you already used the all-interface command
Stop the public tunnel and the existing container before correcting exposure. A container restart does not change its stored port mapping. Replacing a container to change its binding requires preserving the correct volume and image, and should follow a backed-up, reviewed change plan. Do not start two application containers against the same data volume merely to compare bindings.
Secure the first login before remote exposure
Open http://127.0.0.1:8080 in a browser on the Docker host. Keep the tunnel stopped while you complete initial account setup. If you are working on a headless server, use an approved administrative access path rather than broadening the Docker binding just to reach the first-login screen.
The available Oxynote primary-source extracts do not establish a default administrator email, where an initial password appears, how long it remains visible, or the exact password-change workflow. We therefore do not publish a guessed email or password. Follow the installed version's setup interface and version-matched project instructions. If you cannot establish private administrator access, stop here and keep the service unpublished.
Create a strong, unique administrator credential, or replace any bootstrap credential if the installed version provides one. Store it in your approved credential manager. Avoid sharing an administrator account with ordinary readers or editors, and review invitations and permissions before adding sensitive content.
As a deployment acceptance test, end the setup session if supported and verify a fresh login with the intended credentials. If a bootstrap password was used and changed, check that it no longer grants access. This is a recommended test, not a claim that Oxynote automatically performs it or invalidates all existing sessions. Session invalidation and account recovery behavior need version-specific confirmation.
Test unauthenticated access in a fresh browser session as well. Protected workspace content should not be accessible to a visitor who has not been authorized. Oxynote describes its workspaces as invitation-based, but you still need to verify your deployed instance. Do not assume that identity-provider integration, multifactor authentication, or a particular role model is available without checking.
Verify the local application and binding
Inspect state, ports, and storage
docker ps
docker port <container-id-or-name>
docker inspect --format '{{json .Mounts}}' <container-id-or-name>
Replace the placeholder with your actual container ID or generated name. The published port should identify 127.0.0.1:8080. Check that the mounts include oxynote_data at /oxynote/data. If the mapping instead shows an all-interface address, the intended loopback-bound container is not the one you are inspecting.
If the container is absent from the running list, inspect stopped containers and startup output:
docker ps -a
docker logs <container-id-or-name>
Verify a real HTTP response
Use the browser to load the application, complete a fresh authenticated login, and navigate between pages. If curl is installed, this additional request tests whether the endpoint returns HTTP:
curl -I http://127.0.0.1:8080
A redirect or authentication response can still demonstrate HTTP reachability. A HEAD request may also behave differently from a browser GET, so do not declare the application healthy or broken from a single status code. A connection refusal indicates a different class of problem from an application-generated response.
Test storage and exposure boundaries
Create a temporary page, refresh it, and confirm that the content remains. During a planned test, restart the same container and verify the content again. This provides a useful persistence check but does not replace a restore test.
From another authorized LAN device, check that the Docker host's LAN address on port 8080 does not provide access in the loopback-only layout. An unexpected response deserves investigation: another container, another listener, an internal proxy, or an older networking configuration may be exposing the service independently.
Install Localtonet as a Linux service
This path follows our documented Debian/Ubuntu x64 package workflow. On a compatible host, open the Localtonet getting-started documentation and download the Debian/Ubuntu x64 package named localtonet-linux-x64.deb. Use the ARM64 package and its corresponding instructions for ARM64 hardware, not the x64 file.
Create or sign in to your Localtonet account and obtain the device-specific AuthToken for this installation. Treat it as a secret. The package workflow stores it in a protected file rather than placing the literal token in a command line.
Install the downloaded package
Open a terminal in the directory containing the downloaded file and run:
sudo apt install ./localtonet-linux-x64.deb
Set the AuthToken and check configuration
Edit /etc/localtonet/auth-token as root using your approved editor. Replace DUMMY_AUTH_TOKEN with the correct token on a single line. Then protect the file and run the documented check:
sudo chmod 600 /etc/localtonet/auth-token
sudo localtonet --headless --authtoken-file /etc/localtonet/auth-token --check-config
Resolve any reported configuration problem before continuing. Do not paste the token into screenshots, tickets, or shared logs.
Start and enable the service
After the configuration check succeeds, start the normal client service and inspect its journal:
sudo systemctl enable --now localtonet.service
sudo journalctl -u localtonet.service
This HTTP workflow uses localtonet.service, not the separate VPN service. No VPN configuration is needed.
Verify the service and device connection
sudo systemctl status localtonet.service
sudo systemctl is-active localtonet.service
curl -I http://127.0.0.1:8080
Check both layers: systemd should report the client service as active, and the Localtonet dashboard should show the intended device connected. A running process does not by itself prove relay connectivity. Review the journal if the device remains disconnected. Finally, the client host must be able to reach the HTTP target independently of the public tunnel.
Configure and verify the HTTP tunnel
Use an HTTP tunnel for Oxynote's web interface, not a File Server tunnel or a raw database tunnel. The following settings are established by our product documentation context. The available evidence does not include the current HTTP-specific page's complete numbered instructions, so this guide does not present the earlier seven-step arrangement as an exact reproduction of that page. Check the current HTTP tunnel documentation for the dashboard's exact sequence and labels if they differ.
Set the tunnel configuration
In the dashboard's HTTP tunnel configuration, choose the intended Process Type, the connected device's AuthToken, and an available relay server. HTTP Process Types are Random Sub Domain, Custom Sub Domain, and Custom Domain. They provide a public HTTPS address for the target; availability and options can vary. Use current dashboard values for relay selection and current instructions for custom-domain DNS rather than copying a guessed server code or DNS record.
For the same-host deployment in this guide, set the local IP to 127.0.0.1 and the local port to 8080. Save or create the configuration as offered by the current interface, then press Start. Creating a configuration and running the tunnel are separate lifecycle actions.
| Client location | HTTP target | Required boundary |
|---|---|---|
| Directly on the Docker host | 127.0.0.1:8080 | Docker explicitly publishes to host loopback. |
| Another trusted LAN machine | Permitted private address of the Docker host, port 8080 | A deliberate LAN binding and host controls allow the client; loopback publication alone will not work. |
| Behind an existing internal proxy | The approved HTTP proxy endpoint reachable by the client | Verify proxy routing, authentication, and backend restrictions separately. |
Loopback is relative to the process's network environment. Our Linux service runs on the host in this example. If you instead place the client in a separate container, its 127.0.0.1 generally refers to that container, not the Docker host. Do not reuse the same target without validating that different topology.
When the client is on another machine
Prefer the same-host arrangement unless there is a reason to separate the devices. A separate client requires a reachable private endpoint and carefully scoped host access controls before publishing the application. Bind only the intended host interface where practical, allow only the necessary source and port, and verify both allowed and denied access paths. Docker firewall behavior must be considered when evaluating host rules.
Localtonet does not require an inbound internet-facing firewall opening for its relay connection. That does not eliminate the separate need to permit a LAN connection between your client device and the Oxynote host. If policy does not allow that path, keep the client on the host rather than weakening unrelated controls.
Verify the public endpoint
Open the assigned HTTPS address from another device, preferably outside the local network. Confirm that an unauthenticated visitor cannot read protected content, that authorized login works, and that page navigation, editing, and refresh behave correctly. If collaboration is important, test it with two authorized sessions rather than assuming that a successful login exercises every feature.
Stop the tunnel and confirm that remote access through that endpoint ends. The local application should remain available on its intended local path. Restart the tunnel only when needed. Its public address is usable only while the selected client is connected, the tunnel is running, and the application responds.
A public endpoint can be discovered or forwarded beyond the intended audience. Keep authentication strong, permissions narrow, and software maintained. Do not treat an obscure URL as a password, and do not assume public HTTPS encrypts an independently configured LAN HTTP hop.
Operate, back up, and upgrade the deployment
Use the existing container for routine maintenance
docker logs <container-id-or-name>
docker logs -f <container-id-or-name>
docker stop <container-id-or-name>
docker start <container-id-or-name>
docker restart <container-id-or-name>
These are separate operations, not a script to run in sequence. Use the one appropriate to the task. Interrupting a live log view stops the view, not the application. Review logs before sharing them because they can include user identifiers, queries, hostnames, and other private information.
The quick-start command defines no restart policy. Do not assume Oxynote returns automatically after a reboot. Check the existing container and start it if necessary, then verify local HTTP before testing the tunnel. Enabling our systemd client service does not add a Docker restart policy to Oxynote.
Record the actual image and volume
docker inspect --format '{{.Image}}' <container-id-or-name>
docker image inspect ghcr.io/oxynote/oxynote --format '{{json .RepoDigests}}'
docker volume inspect oxynote_data
The container inspection identifies its image. The image inspection reports available repository digests for that local reference, which might have changed since the container was created. Keep those distinctions in your maintenance record along with the application version and backup details.
The available evidence does not establish Oxynote's version-specific upgrade, migration, restore, or rollback procedure. Read the relevant release instructions, test a backup, and plan maintenance before replacing the container or pulling a changed image into production. A data migration can make an older application image incompatible with the modified volume, so retaining an old image alone is not a complete rollback plan.
Do not delete oxynote_data during routine maintenance. Container removal and volume removal are different operations. Avoid destructive cleanup while diagnosing missing data, and do not assume that a successful restart proves backup recoverability.
Maintain the Localtonet service separately
For the documented Linux package upgrade path, install the new compatible package and restart the client. The package workflow preserves its configuration:
sudo apt install ./localtonet-linux-x64.deb
sudo systemctl restart localtonet
sudo systemctl status localtonet.service
Then confirm device connectivity and the intended tunnel state. During planned downtime, stop the tunnel first, perform the maintenance, verify the local application and client, and only then restore remote access.
Connect live metrics with least privilege
Oxynote supports Prometheus, PostgreSQL, MySQL, and MariaDB data sources. Live Metrics blocks can render time series, bar charts, and gauges. The project also describes Grafana-style query macros such as $__rate_interval and $__timeFilter, plus workspace variables whose selected values remain personal to each reader.
This makes operational documentation more useful: a runbook can explain a latency threshold beside the chart that shows it, and architecture notes can display capacity trends. Simulated chart patterns are also available, so make sure an apparent chart is actually backed by the intended live source before using it to make an operational decision.
| Source | Useful context | Access recommendation |
|---|---|---|
| Prometheus | Service health, latency, errors, and saturation | Permit only the required private metric endpoint and network path. |
| PostgreSQL | Selected operational or reporting queries | Use a dedicated read-only user with narrowly scoped access. |
| MySQL | SQL-backed charts in engineering pages | Restrict credentials to the needed schemas, tables, or views. |
| MariaDB | Queries beside procedures that interpret them | Use read-only credentials and an approved private connection. |
Oxynote explicitly calls for read-only SQL users. Do not reuse application credentials with write privileges. The available evidence does not establish exact connection-screen fields, certificate settings, or secret-storage behavior, so validate those details in your deployed version before connecting sensitive systems.
The Oxynote container needs its own working path to each source; host reachability alone is not always sufficient. Publishing the wiki through Localtonet does not create that backend path. Do not expose database or Prometheus ports publicly merely to make charts work.
Oxynote's AI assistant and agent-facing MCP functionality are optional. The project says the assistant stays off until configured, and the wiki can be used without either feature. Treat agent access as a separate permission decision, not an automatic part of publishing the web interface.
Troubleshoot one layer at a time
Port 8080 is already in use
Inspect docker ps and the host's listeners. An earlier Oxynote container may already own the port. Do not keep rerunning docker run. Docker can map a different host port to container port 8080, but that is a deployment variation: update the browser address, binding checks, and Localtonet target together.
The container exits immediately
Use docker ps -a and docker logs. Check the actual error for storage problems, permissions, or application startup failures. Image-download and port-allocation errors may occur before a running application exists. Preserve useful diagnostics, but redact credentials and private infrastructure details.
Localhost does not open Oxynote
Confirm that the browser is on the Docker host and use http://127.0.0.1:8080 explicitly. This avoids an IPv6 localhost lookup when only IPv4 loopback was published. Check the running container, effective mapping, and logs. Local HTTP is expected here; the public HTTPS address is a separate endpoint.
The Localtonet service is active but the device is disconnected
Review sudo journalctl -u localtonet.service, confirm that the correct token is in the protected file, and rerun the configuration check. Verify authorized outbound connectivity. Do not change inbound router rules to troubleshoot a client that has not connected to a relay.
Local access works but the public address fails
Check the selected device, tunnel state, and target. Test the target from the client device itself. A separate LAN client cannot use the Docker host's loopback publication. Conversely, a same-host client should not need a LAN binding for this tutorial's layout.
The page loads remotely but login or navigation fails
Compare the same operation locally and remotely. If both fail, investigate the application and credentials. If only public access fails, inspect browser errors, redirects, and application logs. Do not guess external-URL, cookie, or proxy environment variables. Confirm any required setting against version-matched Oxynote instructions.
Content appears missing after replacement
Inspect the replacement container's mounts and identify the original volume. Stop making changes until the correct data location is understood. A new empty volume, a different Docker daemon, or a missing mount can look like data loss. Do not delete old containers or volumes during this investigation.
Charts fail while the wiki works
Investigate data-source reachability from the application environment, read permissions, query validity, and any required private-network controls. The HTTP tunnel serves the wiki interface; it does not automatically provide backend database connectivity.
Frequently asked questions
Does the upstream Docker command expose only localhost?
No. -p 8080:8080 normally publishes on all host interfaces. This guide instead uses -p 127.0.0.1:8080:8080 for a Localtonet client running directly on the same host.
What are the initial Oxynote credentials?
The supplied primary-source evidence does not establish them. Use the installed version's setup interface and version-matched project guidance. Keep the application unpublished until private administrator access is established and tested.
Can the Localtonet client run on another machine?
Yes, if it can reach an approved private Oxynote endpoint. The loopback-only mapping in this guide will not be reachable from another machine. A separate client requires deliberate private-network publication and appropriate host access controls.
Where is the application data stored?
The command mounts the named Docker volume oxynote_data at /oxynote/data. It provides persistence, not an independent backup. Test a version-appropriate backup and restore procedure before relying on the instance.
Is the image pinned to v0.9.3?
No. The upstream command has no explicit tag or digest and therefore uses the mutable default tag. A project release announcement does not establish which image is running. Record and verify the deployed image separately.
Does creating the tunnel start it?
No. Press Start after configuration. The selected client must remain connected and the application must remain available. You can stop the tunnel without deleting its configuration.
Do I need a VPN, public IP, or database tunnel?
No. Our HTTP workflow uses an outbound client connection without inbound router port forwarding or a public IP. Database and metric-source access should remain on approved private paths. This HTTP tunnel is not VPN functionality.
Can I use Compose or a custom domain?
A verified Oxynote Compose configuration was not supplied, so this guide uses its single-container path. Localtonet HTTP tunnels support custom-domain process types where available; use current documentation for DNS requirements. For broader ingress design, our Docker Compose ingress guide explains publishing a shared local proxy.
Connect your verified Oxynote workspace
Start with a loopback-bound container, establish private account access, and verify persistence. Then connect our client, configure the HTTP target, and start the tunnel only when the workspace is ready for remote users.
Get Started Free โ