Continuing Your Homelab: Operating the Services You Built
Building a homelab is only the beginning. The next stage is learning how to operate the services you deploy: finding the files they use, understanding their containers, choosing storage deliberately, and recovering when something goes wrong.
These notes are adapted from my Continuing Your Homelab presentation for Cybr.Sec.Con 2026. The examples focus on Cosmos Cloud, Docker, Portainer, BookStack, and network-attached storage.
The goal is not to create a perfect platform on the first attempt. The goal is to build enough understanding that you can diagnose, repair, and improve the platform over time.
Download the original PowerPoint presentation
From building to operating
The first homelab presentation covered the initial path: prepare a host, establish remote access, configure DNS, install Docker, and bring up a platform. Continuing the lab means developing an operating model around that platform:
- Know where configuration and application data live.
- Know how to inspect logs and container state.
- Keep compose files and environment variables recoverable.
- Separate disposable containers from persistent data.
- Use a management interface when it improves visibility, but understand the underlying Docker model.
- Back up the data that would be painful or impossible to recreate.
Cosmos Market and ServApps
Cosmos Cloud presents applications as ServApps: a container, a reverse-proxy route, and URI management combined in one interface. The dashboard can provide start, stop, restart, recreate, and kill controls; resource monitoring; live logs; an in-browser terminal; environment-variable editing; and update checks.
For a simple Market installation, the workflow is:
- Open the Cosmos dashboard and select Market in the left sidebar.
- Search for an application such as Files or File Manager.
- Review the application description, repository, Docker Hub link, and compose file.
- Select Install and set the desired hostname.
- Confirm the DNS entry exists, then continue.
- Restart Cosmos if it needs to activate a new reverse-proxy route.
The result is convenient, but convenience does not remove the need to understand the generated configuration. When an application behaves unexpectedly, the compose definition, environment variables, volumes, and logs are still the useful sources of truth.
Learn the important paths
File paths become especially important when editing compose files or recovering from a broken deployment. The presentation calls out these locations and commands:
/var/lib/cosmos
/opt/cosmos/appdata
docker logs cosmos-server
/var/lib/cosmos is the Cosmos configuration home. The cosmos-config.json file there may be useful during recovery. /opt/cosmos/appdata is a recommended location for application bind mounts, with a separate subdirectory per application, such as:
/opt/cosmos/appdata/bookstack
Cosmos also exposes a Docker tab where volumes, environment variables, and labels can be inspected per container. When the location of a configuration file is uncertain, search for it rather than guessing:
sudo find / -name "cosmos-config.json" 2>/dev/null
Why use Portainer when Docker has a CLI?
Docker’s command line is powerful, but a web interface can make routine operations and inspection easier. Portainer CE can provide:
- A single view of containers.
- Browser-based deployment and management of Docker Compose stacks.
- Log inspection, terminal access, and volume browsing.
- Connections to Docker Hub, GHCR, and private registries.
- A visual way to start, stop, inspect, and recreate containers.
Portainer should complement Docker knowledge, not replace it. Always use the official portainer/portainer-ce:lts image rather than an unofficial fork, and prefer the LTS tag for a stable management service.
The official Linux installation pattern from the presentation is:
docker volume create portainer_data
docker run -d \
-p 8000:8000 \
-p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:lts
Verify that the container is running:
docker ps
Then open the HTTPS interface at:
https://<your-server-ip>:9443
The Docker socket mount gives Portainer broad control over the Docker engine. Protect the Portainer account and treat the service as an administrative interface, not an ordinary public-facing application.
Portainer Stacks
Portainer’s Stacks interface provides several deployment paths:
- Web Editor: paste a compose YAML file into the browser.
- Upload: upload a local YAML file.
- Git Repository: pull a compose definition from a repository and redeploy when it changes.
- Custom Templates: save and reuse compose configurations.
All four paths support environment variables and .env loading. Keep secrets out of the compose file and out of public Git repositories. When using a Git repository, review the repository’s access controls and remember that a deployment system with repository access can become part of the application’s trust boundary.
Bind mounts and named volumes
Storage choices determine whether an application is easy to move and recover.
A named volume, such as portainer_data, is managed by Docker. It is convenient for an application’s internal state, but it can be less obvious to inspect or copy from the host. A bind mount maps a known host path into the container, for example:
/opt/cosmos/appdata/bookstack:/config
Bind mounts make the host-side location explicit and work well when application data needs to be backed up to a known directory or stored on a NAS. They also make permissions and ownership your responsibility.
Before changing a mount, confirm what the application expects inside the container. A path that looks correct on the host can still be wrong if it replaces a directory the image needs at startup.
BookStack as a practical application
BookStack is a useful homelab service because it turns the lab itself into documentation. Use it to record:
- Hostnames, addresses, and service URLs.
- Compose files and environment-variable names.
- Storage locations and backup destinations.
- Recovery steps and known failure modes.
- Hardware changes and maintenance history.
Do not store passwords, API tokens, private keys, or recovery codes in an unsecured documentation instance. Documentation is valuable only when it is both available and protected.
Choosing a community image
When selecting an image, distinguish between an official project image, a trusted community image, and an unknown third-party build. Check the project documentation, image source, release cadence, configuration expectations, and update process.
For Portainer specifically, the presentation recommends the official Docker Hub image. The same principle applies to other services: verify the image you are pulling before granting it persistent storage, network access, or host-level capabilities.
NAS storage and network protocols
Keeping application data on a NAS can improve capacity and make centralized backups easier, but it introduces another dependency: the application now depends on the network, the NAS, authentication, and the mount being available during startup.
Common choices include:
- SMB/CIFS: widely supported and familiar in mixed operating-system environments.
- NFS: common in Linux and Unix environments and often a natural fit for Linux hosts.
- Local storage: simpler and usually faster, but tied to the host’s disks and recovery process.
Use the protocol that matches your hosts and operational needs. Test behavior during a network outage and after a reboot. A container that starts before its remote mount is available can create confusing empty directories or write data to the wrong local path.
Keep data on a NAS intentionally
Before moving data, decide what belongs on the NAS and what should remain local. Large media libraries and backups may benefit from centralized storage. Databases and latency-sensitive application state may need local disks, depending on the application and network quality.
Document the mount path, credentials mechanism, ownership, permissions, and startup dependencies. Never put a plaintext NAS password directly into a public compose file. Use a protected credentials file, a secrets mechanism, or another approach appropriate to the host.
Health checks are part of operations
An application showing as “running” does not prove that it is healthy. A useful health check asks whether the service is reachable, whether its dependencies respond, whether it can read and write its storage, and whether its logs show repeated failures.
When investigating a problem, work from the outside in:
- Confirm DNS resolves to the expected host.
- Confirm the reverse proxy route is correct.
- Confirm the container is running.
- Read the container logs.
- Inspect mounts, environment variables, and network attachments.
- Check the application’s own health endpoint or web interface.
Backups before the incident
Backups are not complete until they have been restored successfully. A practical backup plan identifies:
- The data to preserve.
- The destination and retention period.
- How often the backup runs.
- How encryption and credentials are handled.
- How a restore will be tested.
Back up compose files, documentation, application data, and the configuration needed to rebuild the host. Keep at least one backup separate from the machine it protects. A NAS is useful, but it should not be the only copy of important data.
The ghost incident lesson
The presentation closes with a story about an incident that appeared mysterious until the fundamentals were checked. The operational lesson is familiar: inspect the evidence, verify assumptions, and resist changing several variables at once.
When something disappears or stops working, start with DNS, service status, logs, mounts, and recent changes. A calm recovery process is more valuable than a clever guess.