Skip to main content
Daniel J Glover
Back to Blog

Docker Compose self-hosted services guide

10 min read
Article overview
Written by Daniel J Glover

Practical perspective from an IT leader working across operations, security, automation, and change.

Published 7 April 2026

10 minute read with practical, decision-oriented guidance.

Best suited for

Leaders and operators looking for concise, actionable takeaways.

Docker Compose describes how a group of containers, networks and storage volumes fit together. It is useful for a small self-hosted service because the configuration is readable and can be kept in version control. It does not supply patching, tested backups or an engineer to recover the service when it fails.

This guide covers eight service choices and a local BookStack example. The decision is whether owning the service solves a business problem worth the operating effort. Keeping data on your hardware gives you control over its location; it also makes your team responsible for access, recovery and availability.

Choose the service before building the stack

Start with one service whose failure you can tolerate while learning the operating model. A documentation pilot with copies of non-sensitive procedures is a better first experiment than the only password vault your team can access during an outage.

ServiceUseful purposeDecision to make before adoption
PortainerA browser interface for container managementWho needs control of the Docker host, and how will that access be restricted?
BookStackStructured documentation organised into books, chapters and pagesCan a second person recover the documentation when the host is unavailable?
VaultwardenA community implementation compatible with Bitwarden clientsCan the team support a credential store, protect its backups and recover access independently?
Uptime KumaAvailability checks and status informationWill monitoring still operate when the service host or its internet connection fails?
GiteaGit repository hostingWhere are independent repository backups, and what happens if the Git server is down during recovery?
Prometheus and GrafanaMetrics collection and dashboardsWhich measurements lead to an action, and who handles the resulting alerts?
NextcloudFile sharing and collaborationWho manages permissions, storage growth, updates and recovery of shared files?
HomepageA starting page for links and service informationDoes the dashboard need privileged integrations, or will ordinary links do?

These are candidates, not a claim that all eight belong in every stack. Avoid adding an application simply because there is a container image for it. Each additional database, administrator account and update cycle adds work.

Network boundaries need an accurate description

A Compose network groups containers that can communicate. Containers sharing a network may reach each other's listening ports even when those ports are not published on the host. A shared reverse-proxy network can therefore create more connectivity than the public hostname suggests.

Docker's internal network setting creates an externally isolated network. It is useful for a database network, but it does not mean that only one named application can ever reach the database. Other attached containers and the Docker host remain relevant to the threat model. Docker administrators can change the configuration.

Published ports are a separate decision. A mapping such as 8080:80 normally publishes on the host's addresses. A mapping such as 127.0.0.1:8080:80 limits the normal host binding to loopback. Check the installed Engine version and routing configuration: Docker documents older-version and direct-routing exceptions to assumptions about reachability.

For a business deployment, draw the allowed connections: user to application, application to database, backup process to storage, administrator to management interface. Then test those routes from authorised locations. A VLAN diagram alone does not prove the containers follow it. My network segmentation guide covers the wider network design.

A local BookStack example

BookStack is a documentation application. The LinuxServer image documentation defines its container configuration, including APP_KEY, APP_URL, DB_USERNAME and DB_PASSWORD. Those exact names matter: examples using different database variable names may not configure the current image as intended.

The example below is for a local evaluation on a supported Docker Engine and Compose installation. It binds the application to loopback and does not publish the database. It is not a complete internet-facing deployment: TLS, identity integration, host hardening and external access rules require separate decisions.

Select supported, compatible image versions from LinuxServer and the MariaDB official image. Record the exact tags or digests tested. Set BOOKSTACK_IMAGE and MARIADB_IMAGE to those references in a local .env file, along with the numeric PUID and PGID appropriate to the host. The example deliberately requires these choices rather than silently pulling a moving latest tag.

Create three protected local files under secrets/: bookstack_app_key, bookstack_db_password and mariadb_root_password. Use distinct strong database passwords. Generate APP_KEY using the selected image's documented appkey procedure; do not invent a short placeholder or generate a different key each restart. Preserve the application key securely with the recovery material. Do not put any of these values in Git or a support ticket.

services:
  bookstack:
    image: ${BOOKSTACK_IMAGE:?Choose a tested LinuxServer BookStack image}
    environment:
      PUID: ${PUID:?Set the host user ID}
      PGID: ${PGID:?Set the host group ID}
      TZ: Europe/London
      APP_URL: http://localhost:6875
      FILE__APP_KEY: /run/secrets/bookstack_app_key
      DB_HOST: bookstack-db
      DB_PORT: "3306"
      DB_DATABASE: bookstack
      DB_USERNAME: bookstack
      FILE__DB_PASSWORD: /run/secrets/bookstack_db_password
    secrets:
      - bookstack_app_key
      - bookstack_db_password
    volumes:
      - bookstack_config:/config
    ports:
      - "127.0.0.1:6875:80"
    networks:
      - app
      - database
 
  bookstack-db:
    image: ${MARIADB_IMAGE:?Choose a compatible supported MariaDB image}
    environment:
      MARIADB_DATABASE: bookstack
      MARIADB_USER: bookstack
      MARIADB_PASSWORD_FILE: /run/secrets/bookstack_db_password
      MARIADB_ROOT_PASSWORD_FILE: /run/secrets/mariadb_root_password
    secrets:
      - bookstack_db_password
      - mariadb_root_password
    volumes:
      - bookstack_database:/var/lib/mysql
    networks:
      - database
 
secrets:
  bookstack_app_key:
    file: ./secrets/bookstack_app_key
  bookstack_db_password:
    file: ./secrets/bookstack_db_password
  mariadb_root_password:
    file: ./secrets/mariadb_root_password
 
volumes:
  bookstack_config:
  bookstack_database:
 
networks:
  app:
  database:
    internal: true

LinuxServer's FILE__ mechanism and MariaDB's _FILE variables are image-specific ways of reading mounted secret files. They are not interchangeable conventions. Compose secrets grant files to individual services. In a local Compose deployment those source files still exist on the host; this is not an encrypted vault or protection from a host administrator. Set host permissions and backup access accordingly.

Run docker compose config --quiet from the project directory before starting anything. This checks the Compose model and required variable interpolation. It does not prove that the images exist, that credentials work or that the application is secure. A deployment acceptance test must check those separately.

Initialise the database first in the approved local evaluation environment. Confirm its readiness from its logs or the selected image's documented health check before starting BookStack. Merely listing depends_on without a readiness condition would not prove that MariaDB is ready to accept connections.

The MariaDB initialisation variables apply when creating a new database directory. Changing the password file later does not automatically change an existing database account. Plan password rotation through the database and application configuration together, and test that the application reconnects.

The LinuxServer instructions document default BookStack administrator credentials. Change them during the local setup before allowing other users or routes to the service. Keep test content non-sensitive until permissions and recovery have been checked. If the application will use a different public URL, follow the image's documented URL-change procedure and configure the proxy and TLS deliberately.

A reverse proxy is an access decision

A reverse proxy can give several applications consistent hostnames and TLS handling. It is not mandatory for every local service, and a hostname rule is not authentication.

If the proxy discovers containers through the Docker socket, account for the privileges that connection provides. Mounting /var/run/docker.sock with :ro does not turn the Docker API into a read-only API. A compromise of a component with powerful daemon access can threaten the host. Review the specific proxy access controls or use a configuration that does not require direct daemon access.

Keep management interfaces such as Portainer on an authorised management path. Do not add a public router and then rely on a sentence saying the service is private. Check the actual host bindings, proxy routes, firewall rules and authentication from the locations that matter.

A dashboard such as Homepage does not automatically need Docker socket access. Begin with links. Add integrations only where the operational value justifies their credentials and permissions.

Make monitoring independent enough to be useful

Uptime Kuma can answer whether a configured endpoint responds. Prometheus and Grafana can help explain resource use and application behaviour. Neither arrangement proves that a customer can complete a transaction simply because a port is open.

Choose checks around the service: can an authorised test user reach a non-destructive page, is storage filling, did the last backup complete, and has a certificate approached its renewal threshold? Keep check credentials narrowly scoped and avoid probes that submit orders, send messages or change business data.

If Prometheus is intended to be internal-only, do not attach it to a shared proxy network by accident. Its scrape targets must still be reachable through explicitly allowed routes. Document those routes instead of assuming an isolated network can reach every exporter. Keep an independent availability check outside the host's own failure boundary where the service warrants it.

Back up the application, not just its container definition

Compose files describe the deployment. They do not contain the database contents, uploaded files or every secret needed for recovery. For BookStack, retain a consistent database backup, application files and configuration, and the protected recovery secrets. Follow the application's backup and restore guidance rather than copying a live database directory and assuming it is consistent.

For Gitea, account for repositories, database records, attachments and configuration. Never commit private SSH keys or application secrets to the repository as part of an infrastructure baseline. For Vaultwarden, treat backup confidentiality and recovery access as requirements before moving shared credentials into it. A backup stored only on the same failed host is not an independent recovery path.

Use an isolated restore environment. Confirm that the restored application contains the expected records and files and that permissions still work. Prevent it from sending production messages or writing to connected business systems. My backup and disaster recovery guide explains how to plan that evidence.

Updates need a supported destination and a rollback plan

Pinning an image improves repeatability. It does not make an obsolete release safe. Record the running version, support status, release notes, database migration requirements and tested destination before updating. A digest fixes image content but still needs a planned replacement when security fixes arrive.

Some application updates change the database. Reverting an image tag may therefore be insufficient or unsafe. Retain an application-consistent backup and rehearse the documented recovery path before a consequential upgrade. Use scanning results as one input, alongside vendor advisories and the way the service is exposed.

A worked adoption decision

Suppose a small team wants searchable operating procedures and has one engineer available for maintenance. Its initial candidate is BookStack, with a second staff member responsible for the recovery instructions. The pilot succeeds only if both people can find procedures, access is appropriate, a separate backup exists and the second person can restore it in isolation.

If the pilot cannot meet those conditions, adding a password manager and file-sharing platform would multiply the dependency on that engineer. A managed documentation service may be the more useful choice. If the recovery exercise passes and the maintenance effort is acceptable, the team has evidence for adopting this one service and evaluating the next separately.

Self-hosting can provide control, but control has to include who maintains the system when its usual owner is absent. If you need help choosing the services, defining their access boundaries or testing a recovery plan, book a technical consultation. Bring the proposed service list, existing hosting constraints and the business processes that depend on them.

Share this post

About the author

DG

Daniel J Glover

IT Leader with experience spanning IT management, compliance, development, automation, AI, and project management. I write about technology, leadership, and building better systems.

Continue exploring

Keep building context around this topic

Jump to closely related posts and topic hubs to deepen understanding and discover connected ideas faster.

Browse all articles

Evaluating Self-Hosted Infrastructure?

Self-hosted services give you control but need solid foundations. Book a free 30-minute infrastructure review to understand whether your setup is ready for production scale.

Infrastructure review

Get Occasional IT Leadership Insights

IT leadership insights, occasionally. No fluff. Unsubscribe any time.

No spam. Unsubscribe any time.