CTRoadmap maps a homelab and refuses to touch it
Homelab Server Network Diagram & Documentation for Mapping Function Topology
At a glance
- What is it?
- CTRoadmap is a Docker-served browser app for drawing a homelab as nodes, services, storage and the relationships between them, saving everything to one JSON file. The hard line it draws is that it documents and never interfaces: no monitoring, no Docker socket, no commands run from the web app.
- Who is it for?
- CTRoadmap suits someone with a mixed homelab who wants one browsable picture of what talks to what and needs that picture to survive a rebuild. It will not suit you if you want live status, alerting or automatic inventory, because the project deliberately mounts no Docker socket and runs nothing on your hosts.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It documents the homelab and never touches it
The stance is stated in the first paragraph and repeated later for emphasis: CTRoadmap does not monitor, control, or interface with your homelab at all. It is meant to be a step up from PowerPoint and similar diagram apps, and it is a stand-alone repository of your system rather than an integrated part of it.
Three details make that boundary real rather than aspirational. The web application does not execute shell commands, Docker commands, or the host updater, and it does not mount the Docker socket. The update system is called advisory only. Even the release notes for the newest beta describe the application as telling you an update exists while you remain in control of when anything runs on the host.
That boundary costs you the thing most homelab dashboards sell, which is live state. Nothing here reports whether a container is up. You get the topology you drew and the relationships you typed, which is exactly what you want the day a machine dies and you need to remember what was on it.
The Atlas is one JSON file behind two bind mounts
Everything you type goes into the Atlas, saved to the data/atlas.json file, and the persistence story is short enough to read in one sitting. The compose file bind-mounts two host directories into the container:
services:
ctroadmap:
build: .
container_name: ctroadmap
ports:
- "8088:8088"
volumes:
- ./data:/app/data
- ./exports:/app/exports
restart: unless-stoppedThe installer seeds both directories, and the Dockerfile copies data and exports into the image at build time so a fresh container starts with somewhere to write. For the default install those paths are ~/ctroadmap-beta/data and ~/ctroadmap-beta/exports.
One flat JSON document has a consequence worth planning for. It is trivially versionable, trivially greppable, and trivially backed up, and the update screen leans into that with a BACKUP ATLAS action that saves the current Atlas and starts a timestamped JSON download before anything else happens. It also means two people editing the same homelab at the same time are editing one file, and the documentation does not record what any of it looked like three rebuilds ago unless you keep your own copies.
The install path pulls a beta image; the repo compose file builds
There are two different ways to get the same app, and the instructions make the recommended one explicit. Beta users pull a published image and skip the toolchain entirely: no clone, no Python, no Node, no npm. The requirements list is otherwise ordinary: a Linux server, Docker, Docker Compose v2, curl, Bash, sha256sum, standard utilities and CA certificates. Port 8088 has to be reachable if you open the app from another machine.
curl -fsSL https://raw.githubusercontent.com/NoobCity99/CTRoadmap/main/CTR_install.sh -o CTR_install.sh
chmod +x CTR_install.sh
./CTR_install.shThe script creates the installation, starts the container, and installs or registers the host-side ctr_update.sh updater. A one-line variant pipes the script straight into bash, and CTR_INSTALL_DIR moves the default ~/ctroadmap-beta somewhere else:
CTR_INSTALL_DIR=/opt/ctroadmap-beta ./CTR_install.shWorth knowing which compose file you are on. The installer path uses the published image ghcr.io/noobcity99/ctroadmap:beta, while the compose file in the repository root says build: . and compiles the frontend and backend from source. Synology, NAS and Portainer users get pointed at a third-party search page rather than a documented procedure, so on those platforms you are assembling the compose file yourself.
The uninstaller stops rather than guesses
Removing CTRoadmap takes a script and a decision. Download it the same way the installer was fetched, then run it:
curl -fsSL https://raw.githubusercontent.com/NoobCity99/CTRoadmap/main/CTR_uninstall.sh -o CTR_uninstall.sh
chmod +x CTR_uninstall.sh
./CTR_uninstall.shBy default that stops CTRoadmap and preserves the installation and its persistent data, which is the right default for a machine you may want to look at again. A custom location takes CTR_INSTALL_DIR, and full deletion needs you to type DELETE. The word is in capitals on purpose.
The advanced behaviour is where this project is unusually careful. The uninstaller validates the exact installation before removing anything, falls back to sudo only when protected container-created files remain, and can still recover a damaged Compose configuration by matching the local data and exports directories or the expected container and its bind mounts. If it cannot identify the installation confidently, it stops instead of guessing. Full deletion removes only the matched installation and the exact unused image reference it can identify, leaving other image tags, unrelated helper files, networks and test logs alone. That restraint costs you nothing and saves you a bad afternoon.
ctr_update.sh runs on the host, never from the browser tab
Version 0.8 added the host updater, and its design is the clearest statement of the project's philosophy. The application shows the running version, the latest available version, the update method, the updater status, the release notes and the result of the last host update, then hands you a command instead of pressing a button that runs something. For a normal Linux install the command is:
cd ~/ctroadmap-beta
./ctr_update.shWhat that script does is enumerated in the README: validate the installation, check Docker and Docker Compose, prevent two updater runs from colliding, pull the current release image, recreate the container, check /api/health to confirm CTRoadmap came back, and record the result so the application can report it next time.
What it does not do matters as much. It does not modify Atlas content, prune Docker resources, install packages, silently use sudo, or migrate the installation directory. There is no automatic rollback: if an update fails, the updater leaves your persistent Atlas and exports untouched and reports diagnostics so you can fix the cause before retrying. On a documentation tool that only ever runs when you tell it to, that is a defensible design. On a fleet you are trying to standardise across twenty machines, running the command twenty times by hand is the cost you are signing up for.
Four setup states sit between an old install and an update
Installs created before 0.8 sometimes meet a setup or recovery message instead of a normal update command. The states named in the README are FINISH UPDATE SETUP, REPAIR REQUIRED, UPDATER REFRESH REQUIRED and LEGACY UPDATE METHOD DETECTED, and the documentation is emphatic that these are not requests to reinstall the application.
What they mean is that the host updater needs registering or repairing. The command for that uses --register-only, which registers the updater and stops there: it does not install the application update at the same time. After it finishes you return to Settings, then Updates & App Data, then Updates, choose Check Now, and run the normal update command separately if an update is still pending. Two commands where one would do, on purpose.
One gap is worth flagging for anyone relying on these pages. The README text ends in the middle of the v0.8 update walkthrough, right after the recovery steps, so treat whatever followed that point as undocumented and confirm behaviour against the release notes for the tag you are on.
The Dockerfile still calls itself 0.4.0-beta
The repository is typed as TypeScript at the top level, but the runtime is Python. The Dockerfile is a two-stage build: node:22-alpine compiles the frontend with npm ci and npm run build, then the artifacts land in a python:3.12-slim image that installs backend/requirements.txt and starts uvicorn on 0.0.0.0:8088. So the code you read for the UI is not the code that serves it.
The build arguments are where this gets interesting. CTR_VERSION defaults to 0.4.0-beta, with CTR_BUILD_SHA and CTR_BUILD_DATE defaulting to unknown, and those values become both environment variables and OCI image labels. The releases in this repository have reached beta-v0.8.0. A build that does not pass CTR_VERSION therefore stamps 0.4.0-beta into its environment and labels, and the image description in the Dockerfile calls the product a local-first infrastructure atlas.
Neither the Dockerfile nor the compose file defines a healthcheck, so restart: unless-stopped is the only restart policy in play and readiness is whatever /api/health says once uvicorn is up. The port is published straight to the host as 8088, and no authentication, TLS or reverse proxy step appears anywhere in the installation instructions. Put it behind something before it leaves your LAN.
The gap between the picture and the running system
CTRoadmap competes less with other homelab software than with the drawing you would otherwise make in a generic editor. diagrams.net gives you a canvas and nothing else: shapes, connectors, no notion of a service or a script, and no structure you can query later. Netbox sits at the other end, modelling devices, sites and addresses in a schema you can query with a database, which is what you want for inventory and change records but not for sketching why your media box calls your NAS. CTRoadmap's middle position is the homelab vocabulary itself: nodes, services, storage, scripts, configs, URLs and operational relationships, laid out as a picture.
That middle position is why the project is honest about its edges. There is no live status, no alerting, no automatic inventory, and no auth layer described. It is a beta channel with releases roughly monthly between August and September 2026, the last push on the repository was on 2026-09-21, and it is not archived. The licence is Apache-2.0.
Judge it on whether you will maintain the picture, not on whether it can see the machines. If your homelab documentation is currently a folder of screenshots and a memory you no longer trust, this gives it a home and a backup button. If nobody is going to update the Atlas when you add a service in six months, the file will be wrong, and no amount of topology in it will change that.
Editorial conclusion
CTRoadmap suits someone with a mixed homelab who wants one browsable picture of what talks to what and needs that picture to survive a rebuild. It will not suit you if you want live status, alerting or automatic inventory, because the project deliberately mounts no Docker socket and runs nothing on your hosts. Before adopting it, read the two mount paths in the compose file and confirm they sit on storage you back up, then type the exact word DELETE only when you mean it. Pin the beta tag you tested against, because the Dockerfile default is older than the current release.
Frequently asked questions
What is CTRoadmap?
CTRoadmap is a self-hosted Docker webapp for documenting a homelab as nodes, services, storage, scripts, configs, URLs and the relationships between them. It saves the system documentation to a data/atlas.json file and serves a browser interface on port 8088.
Does CTRoadmap connect to my homelab servers?
No. It does not monitor, control, or interface with your homelab at all, and the web application does not execute shell commands, Docker commands, or the host updater. The container does not mount the Docker socket.
How does CTRoadmap update itself?
The application only tells you that an update exists and can copy a command for you to run yourself. That command runs ctr_update.sh on the host, which validates the installation, pulls the release image, recreates the container and then checks /api/health to confirm it came back.
Where does CTRoadmap store my documentation on disk?
In the Atlas, saved to the data/atlas.json file inside the container. The compose file mounts ./data and ./exports from the host, so for the default install the files sit under ~/ctroadmap-beta/data and ~/ctroadmap-beta/exports.
What happens if a CTRoadmap update fails?
There is currently no automatic rollback. The updater leaves your persistent Atlas and exports alone and reports diagnostics so the problem can be corrected before you retry. The update screen shows the result of the last host update.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/noobcity99-ctroadmap)