
Run a private developer documentation browser locally, verify it with Docker, and expose it only when remote access is needed
DevDocs combines many API reference sets in a fast browser interface with search, keyboard navigation, offline support, and a consistent layout. In this guide, we first install the official DevDocs container, verify the documented local endpoint, and cover the Docker operations needed to maintain the service. We also explain the source-build and manual Ruby paths without mixing them into the recommended container workflow. After the local server is working, we connect it to a Localtonet HTTP tunnel so an authorized remote browser can reach it without inbound router port forwarding, firewall changes, VPN setup, or a public IP address.
📋 What's in this guide
What DevDocs is and what this setup provides
DevDocs is an API documentation browser that brings multiple developer reference sets into one organized web interface. Its focus is fast access to API and reference material rather than long-form programming tutorials. The interface includes instant search, a mobile version, dark theme support, keyboard shortcuts, and offline functionality. Users can select the documentation sets they need instead of loading every available reference into the browser.
The application has two major pieces. A Ruby scraper generates documentation and metadata, while a client-side JavaScript application presents that content through a small Sinatra and Sprockets application. Search and much of the application behavior happen in the browser. DevDocs also uses browser features including a service worker and localStorage to improve startup behavior and support its offline-oriented design.
For readers who only need the maintained public service, the DevDocs project recommends its hosted site. Self-hosting is useful when we want a locally controlled endpoint, a repeatable internal deployment, or a server that can be made available to a particular remote workflow on demand. It does not change DevDocs into a tutorial platform or a full-text search engine. Its content remains focused on structured API and reference documentation pulled from upstream sources.
http://localhost:9292.
The DevDocs repository states that the project is searching for maintainers. It also states that its published container images are automatically built and updated monthly with the latest documentation. Treat those as separate facts: monthly image builds describe the current image process, while the maintainer notice is relevant when evaluating long-term deployment risk. Test updates before relying on them in an important environment.
Prerequisites and deployment plan
The recommended path requires a machine with Docker installed and running. The machine must be able to download an image from GitHub Container Registry, and host port 9292 must be available. You also need a recent compatible browser. The DevDocs project lists recent Firefox, Chrome, or Opera versions, Safari 11.1 or later, Edge 17 or later, and iOS 11.3 or later as its browser baseline.
Docker installation differs across Windows, macOS, and Linux, so this guide does not invent a platform-specific package command. Complete the supported Docker installation for your operating system, start its engine, and then confirm that the client can communicate with the engine:
docker version
docker ps
The first command reports Docker client and server information. The second should return a container list, even if the list is empty. A permission error, missing command, or inability to connect to the daemon must be resolved before installing DevDocs.
Check whether another container already uses the intended name:
docker ps -a --filter name=devdocs
You should also check whether port 9292 is already assigned to another application. The exact operating-system command for inspecting ports varies, but a practical cross-platform check is to look at the published ports of running Docker containers:
docker ps
If an existing service already owns host port 9292, stop or reconfigure that service before following the exact recommended DevDocs command. Although Docker can map a different host port to container port 9292, the official quick-start evidence specifically documents 9292:9292. This guide keeps that mapping so the expected endpoint remains unambiguous.
Additional requirements for remote access
Localtonet is a separate next step, not a substitute for installing DevDocs. For that stage, install and run our client application on the same device as DevDocs, or on another device that can reach the DevDocs host and port. You need a device-specific Localtonet authentication token and must select a relay server or region from the current dashboard. Tokens and server codes must come from your account and current product interface. Do not copy placeholder values from articles or expose a real token in screenshots, terminal history, source control, or support messages.
| Requirement | Why it is needed | How to confirm it |
|---|---|---|
| Docker engine | Runs the official DevDocs container image | docker version returns client and server details |
| Registry access | Downloads the image from GitHub Container Registry | The image pull or docker run completes successfully |
| Available port 9292 | Publishes the DevDocs HTTP service on the host | No conflicting container or process is using the port |
| Compatible browser | Runs the client-side DevDocs interface and browser storage features | The local page loads and search/navigation work |
| Localtonet client and device token | Creates the outbound connection used for optional remote access | The selected device appears connected in the dashboard |
Install DevDocs with the official Docker image

The DevDocs project recommends Docker as the easiest local installation method. The published standard image is ghcr.io/freecodecamp/devdocs:latest. An Alpine-based image is also available as ghcr.io/freecodecamp/devdocs:latest-alpine. The Alpine variant is described as smaller, but the standard image is the clearest starting point because it is used in the project's primary quick-start command.
Confirm that Docker is ready
Run docker version and docker ps. Continue only when Docker can communicate with its engine and no existing container or service conflicts with the name devdocs or host port 9292.
Run the published DevDocs container
Start the official standard image in detached mode with the documented container name and port mapping:
docker run --name devdocs -d -p 9292:9292 ghcr.io/freecodecamp/devdocs:latest
Confirm that the container remains running
Inspect the running-container list and then review the container logs if the service is not shown or exits unexpectedly:
docker ps --filter name=devdocs
docker logs devdocs
Open the documented local endpoint
Visit http://localhost:9292 from a browser on the Docker host. Do not create a remote tunnel until this local request succeeds and the application behaves as expected.
The --name devdocs argument assigns a stable container name, making later start, stop, log, and removal commands easier. The -d argument runs the container in the background. The -p 9292:9292 argument publishes container port 9292 as host port 9292. The final argument identifies the standard published image.
A published Docker port may be reachable through more than the loopback interface, depending on the Docker host, its networking mode, and host firewall policy. The DevDocs quick start identifies localhost:9292 as the local endpoint, but you should still inspect your host exposure and firewall rules. Do not assume that “local container” automatically means “accessible only from this computer.”
Verify the DevDocs service before exposing it

Verification should cover more than seeing an open browser tab. Confirm the container state, the HTTP response, the main interface, a documentation set, and normal browser behavior. This separates application problems from tunnel problems and makes later troubleshooting much faster.
Check the container state
docker ps --filter name=devdocs
The result should show the devdocs container as running and should display the port publication for 9292. If the container is absent from the running list, inspect all containers and its logs:
docker ps -a --filter name=devdocs
docker logs devdocs
A container can be created successfully and still stop because of a runtime problem. This distinction matters: a created container is not evidence that the web application is currently available.
Test the local HTTP endpoint
Open the following address on the Docker host:
http://localhost:9292
Confirm that the DevDocs interface appears. Test search, open a reference entry, navigate between pages, and reload the application. DevDocs is heavily browser-based, so a basic server response alone does not prove that all client-side behavior works.
If you use the manual installation path described later, the project notes that the first request can take a few seconds while assets compile. The published container path may have different startup characteristics, so avoid assigning a fixed readiness time that the project does not document. Review the logs and retry after the container has started rather than treating one immediate failure as conclusive.
Check the intended documentation sets
DevDocs lets users choose their own collection of documentation. Verify that the references needed by your team or workflow are available and usable. Do not assume that self-hosting turns DevDocs into a mirror of every tutorial, guide, or page from each upstream project. DevDocs intentionally focuses on API and reference content that fits its indexing model.
If http://localhost:9292 does not work, do not troubleshoot Localtonet yet. Fix the container, image, port, or DevDocs issue first. A tunnel forwards traffic to a local target; it cannot make an unavailable target healthy.
Routine Docker operations and updates
A self-hosted service needs a small operational playbook. Keep the container name stable, inspect logs before recreating it, and test each update locally before restoring remote access.
Stop and start DevDocs
docker stop devdocs
docker start devdocs
Stopping the container makes the local endpoint unavailable. Any Localtonet tunnel that still points to port 9292 will no longer have a working upstream service. Starting the Docker container again restores the local process, but you should verify the local URL before relying on remote access.
Restart the container
docker restart devdocs
A restart is useful after a transient runtime issue, but it is not an update. Restarting continues to use the image from which the current container was created.
Review logs
docker logs devdocs
To follow new output while testing the browser endpoint, use:
docker logs -f devdocs
Stop following the output with the terminal interrupt appropriate to your shell. Logs can help distinguish startup failures, application errors, and requests that never reached the container.
Replace the container with the current published image
DevDocs states that its published images are built and updated monthly with the latest documentation. Docker does not automatically replace an existing container merely because the tag now points to a newer image. A controlled replacement workflow is:
docker pull ghcr.io/freecodecamp/devdocs:latest
docker stop devdocs
docker rm devdocs
docker run --name devdocs -d -p 9292:9292 ghcr.io/freecodecamp/devdocs:latest
Verify http://localhost:9292 again after replacement. The official quick start does not document a volume mapping or a complete persistence and backup model for this container command, so this article does not invent one. If your browser or deployment depends on locally changed state, investigate and test that state explicitly before removing the old container.
The latest tag can change. Before using DevDocs as an important internal service, define how you will test updates and retain a known working image reference. The supplied project evidence does not establish a release schedule, support guarantee, or rollback policy, so we cannot claim one.
Alternative installation paths
The published image is the recommended choice for a straightforward server. DevDocs also documents building the Docker image from source and performing a manual Ruby installation. These alternatives are useful for contributors, custom image workflows, or environments where the prebuilt image is not the intended deployment artifact.
| Installation path | Best fit | Key requirements |
|---|---|---|
| Published standard image | Fastest recommended local deployment | Docker and access to GitHub Container Registry |
| Published Alpine image | A smaller published container variant | Docker and the latest-alpine image |
| Build image from source | Testing repository code or controlling the local image build | Git, Docker, source checkout, and build resources |
| Manual Ruby installation | Development or operation outside Docker | Ruby 4.0.6, libcurl, Bundler, and an ExecJS-compatible JavaScript runtime |
Use the Alpine-based published image
The project publishes ghcr.io/freecodecamp/devdocs:latest-alpine as its smaller Alpine-based alternative. To use it with the same documented name and port mapping:
docker run --name devdocs -d -p 9292:9292 ghcr.io/freecodecamp/devdocs:latest-alpine
Do not run this while another container named devdocs exists or while host port 9292 is already occupied. Choose one image path, verify it, and keep the operational procedure consistent.
Build the Docker image from source
DevDocs documents the following source-build sequence:
git clone https://github.com/freeCodeCamp/devdocs.git && cd devdocs
docker build -t devdocs .
docker run --name devdocs -d -p 9292:9292 devdocs
The first command clones the repository and enters its directory. The second builds the repository Dockerfile into a local image tagged devdocs. The third starts a container from that local image. This does not provide automatic synchronization with later repository changes. To rebuild newer code, update the checkout, build again, replace the old container, and verify the result.
Install manually with Ruby
The documented manual path requires Ruby 4.0.6 as defined by the project Gemfile, libcurl, and a JavaScript runtime supported by ExecJS. The project notes that a suitable runtime is included on macOS and Windows, while Linux requires Node.js. Package names and installation commands vary by operating system, so verify those prerequisites through the operating system's current supported package channel.
After the prerequisites are installed, the documented application sequence is:
git clone https://github.com/freeCodeCamp/devdocs.git && cd devdocs
gem install bundler
bundle install
bundle exec thor docs:download --default
bundle exec rackup
Then open http://localhost:9292. The project notes that the first request can take several seconds to compile assets.
The documentation-management commands are also important for a manual deployment. List available documentation and versions with:
bundle exec thor docs:list
Download selected documentation by naming it, for example:
bundle exec thor docs:download html css
Update all installed documentation sets with:
bundle exec thor docs:download --installed
Download every documentation set currently available to the project with:
bundle exec thor docs:download --all
The project states that the manual installation has no update mechanism beyond pulling current code from the main branch and downloading the latest installed documentation:
git pull origin main
bundle exec thor docs:download --installed
These operations update different layers. The Git command updates application source, while the Thor command updates the documentation sets already installed. Test both the server and documentation behavior after an update.
Provide remote browser access with Localtonet

Complete this stage only after DevDocs works locally. Our client establishes an outbound connection to a Localtonet relay server, so the workflow does not require inbound router port forwarding, firewall changes, VPN setup, or a public IP address. An HTTP tunnel points to the local DevDocs IP address and port, then provides a public HTTPS URL while the selected client is connected and the tunnel is running.
This is standard HTTP tunneling, not VPN functionality. Localtonet VPN Manager is our separate private mesh VPN feature. For a browser application with a known local HTTP endpoint, an HTTP tunnel is the direct fit.
Install and run the Localtonet client
Run our client on the DevDocs host or on a device that can reach the DevDocs service. Confirm once more that http://localhost:9292 works when the client is on the same machine. If the client is elsewhere, verify that device can reach the actual DevDocs host address and port before creating the tunnel.
Authenticate or select the client device
Use the device-specific authentication token assigned through your Localtonet account. Keep it secret. A token identifies the client device that runs the tunnel and must never be guessed, embedded in an article, or shared publicly.
Select an available relay server
Choose a server or region from the current Localtonet dashboard. Available values can vary, so obtain them from the live product rather than copying a hardcoded server code from a tutorial.
Create an HTTP tunnel to DevDocs
Configure an HTTP tunnel with the DevDocs local target. When our client runs on the same host, use the loopback address 127.0.0.1 and port 9292. HTTP tunnels may use Random Sub Domain, Custom Sub Domain, or Custom Domain as the Process Type. Choose only an option available in your current dashboard and plan.
Start the tunnel
Use the Start button after reviewing the target. Creating a tunnel does not mean it is running. The DevDocs public address becomes usable only while the selected device is connected and the tunnel is running.
Test the assigned public URL
Open the assigned HTTPS URL from a separate browser or network. Test the interface, search, reference navigation, and reload behavior. When remote access is no longer needed, stop or delete the tunnel.
For the current interface and exact field presentation, consult our Localtonet HTTP tunnel documentation. Custom-domain DNS requirements can change and are not established by the evidence supplied for this article, so check the current documentation before configuring DNS.
There are three independent states to check: the DevDocs container must be running, the Localtonet client device must be connected, and the HTTP tunnel must be started. A saved tunnel configuration alone does not make DevDocs remotely available.
Security and exposure considerations
A private local service and a publicly reachable URL have different risk profiles. Before starting the tunnel, decide who should be able to use the endpoint and whether DevDocs itself provides the access controls required by your environment. The supplied DevDocs evidence does not document built-in user authentication for this deployment, so we should not claim that the application protects the public endpoint with accounts, passwords, roles, or authorization.
If the application does not enforce the controls you need, do not assume that an unguessable URL is sufficient protection. Apply an appropriate access-control layer supported by your current architecture, limit exposure to the necessary period, and follow least-privilege policies. Exact Localtonet authentication or restriction options are not established in the supplied context and may vary by current product capability or plan, so verify the dashboard and documentation rather than relying on an unsupported claim.
Do not expose private modifications, internal reference material, embedded credentials, or other sensitive content through DevDocs. Review the actual service from an external browser, use appropriate authorization controls, and stop the tunnel when access is no longer necessary.
Troubleshooting the complete workflow
The container name is already in use
Docker requires container names to be unique. Inspect the existing object:
docker ps -a --filter name=devdocs
If it is the intended DevDocs container, start it rather than creating another one:
docker start devdocs
Remove it only after confirming that replacement is appropriate:
docker rm devdocs
A running container must be stopped before ordinary removal.
Docker reports that port 9292 is already allocated
Inspect running containers with docker ps and identify any existing publication of port 9292. A non-Docker process can also own the port. Stop or reconfigure the conflicting service, then rerun the documented DevDocs command. Avoid changing several variables at once, since that makes later Localtonet target configuration harder to verify.
The container exits immediately
docker ps -a --filter name=devdocs
docker logs devdocs
Read the first relevant error rather than repeatedly restarting the container. If an image download was incomplete or the current image behaves unexpectedly, pull it again and recreate the container only after understanding that container removal is appropriate for your deployment.
The browser cannot open localhost:9292
Confirm the container is running and the port is published. Make sure the browser is running on the Docker host when using localhost. From a different computer, localhost refers to that other computer, not the DevDocs host. Resolve local addressing and firewall behavior before adding a tunnel.
The page loads but the interface does not work correctly
Test with a browser version inside the project's supported baseline. Check browser developer tools for failed requests, disable interfering extensions for a test, and review the container logs. Because DevDocs relies substantially on client-side JavaScript, a returned HTML page does not by itself establish that the application is fully functional.
The public URL returns an error
Work through the chain in order:
- Open
http://localhost:9292on the DevDocs host. - Confirm the
devdocscontainer is running. - Confirm the Localtonet client device is connected.
- Confirm the HTTP tunnel is started rather than merely created.
- Confirm its local target is the reachable DevDocs address and port 9292.
- Test the assigned public URL again from a separate browser or network.
If our client runs on another machine, 127.0.0.1 points back to the client machine, not to the Docker host. In that topology, the tunnel target must be an address through which the client device can actually reach DevDocs. Verify that private network path directly before changing tunnel settings.
Local access works after an update, but expected documentation is missing
Container and manual deployments update differently. For manual installations, use bundle exec thor docs:list to inspect available sets and bundle exec thor docs:download --installed to update installed documentation. The Docker image workflow depends on the contents of the image being run. Confirm that you replaced the old container after pulling the newer image, since pulling an image alone does not alter an existing container.
Frequently asked questions
What is the recommended way to run DevDocs locally?
The DevDocs project recommends Docker as the easiest local method. Its quick start runs ghcr.io/freecodecamp/devdocs:latest in a container named devdocs, publishes port 9292, and makes the application available at http://localhost:9292.
Can I use the Alpine DevDocs image instead?
Yes. The project publishes ghcr.io/freecodecamp/devdocs:latest-alpine as a smaller Alpine-based image. Use the same container port 9292 and verify the service locally before adding remote access.
Does Localtonet install or host DevDocs for me?
No. DevDocs runs on your Docker host or manual Ruby environment. With Localtonet, our HTTP tunnel forwards requests to that existing local service. Install and verify DevDocs first, then configure the tunnel as a separate networking step.
Does creating a Localtonet tunnel make it immediately available?
No. A tunnel must be started after it is created. The selected client device must also remain connected, and the DevDocs container must remain running. The public endpoint is available only while all required parts of that chain are active.
Do I need router port forwarding or a public IP address?
No. Our Localtonet client establishes an outbound connection to a relay server. This allows the tunnel to provide a public URL without inbound router port forwarding, firewall changes, VPN setup, or a public IP address.
Is a Localtonet HTTP tunnel the same as a VPN?
No. An HTTP tunnel publishes the specific DevDocs web service through a public URL. Localtonet VPN Manager is our separate private mesh VPN feature. This tutorial uses standard HTTP tunneling, not VPN functionality.
How are DevDocs documentation sets updated?
The project states that published container images are automatically built and updated monthly with the latest documentation. Existing containers are not automatically replaced when a tag changes, so pull the current image, recreate the container, and verify it. For manual installations, update application code with git pull origin main and installed documentation with bundle exec thor docs:download --installed.
Can the Localtonet client run on a different device?
Yes, provided that the selected client device can reach the DevDocs host and port. In that arrangement, do not use 127.0.0.1 unless DevDocs also runs on the client device. Configure the local target with an address that is actually reachable from the connected client.
Connect your verified DevDocs server with Localtonet
Start with a working service at http://localhost:9292, then create an HTTP tunnel to provide on-demand remote browser access without inbound router configuration.