Self-hosting

Docker Basics Training Guide

A practical beginner-friendly guide to Docker, containers, images, volumes, networks, Compose, backups, and everyday self-hosting commands.

Updated 17/06/2026 DockerComposeContainersSelf-hostingHomelab

What Docker is

Docker packages applications into isolated units called containers. A container bundles the application, runtime, dependencies, and startup configuration so it can run consistently across machines.

Docker is especially useful for self-hosting because it lets you run apps like Firefly III, databases, importers, dashboards, and helper services without installing all of their dependencies directly onto the host operating system.

The core mental model

Image  --run-->  Container
  |                 |
  |                 +-- ports: host:container, e.g. 8080:80
  |                 +-- volumes: persistent data storage
  |                 +-- networks: private communication between containers
  |
  +-- downloaded from a registry or built from a Dockerfile
ConceptMeaningAnalogy
ImageRead-only package/template for an appApp installer / blueprint
ContainerRunning instance of an imageThe running app
VolumePersistent Docker-managed storageExternal data disk
Bind mountHost folder mounted into a containerShared folder
NetworkPrivate virtual network between containersMini LAN inside Docker
RegistryPlace where images are storedApp store for images

First commands

docker run hello-world

docker run -d \
  --name my-nginx \
  -p 8080:80 \
  nginx:latest

Open http://localhost:8080 to see the web server.

Stop and remove it:

docker stop my-nginx
docker rm my-nginx

Common daily commands

TaskCommand
List running containersdocker ps
List all containersdocker ps -a
Start a containerdocker start NAME
Stop a containerdocker stop NAME
Restart a containerdocker restart NAME
Remove a containerdocker rm NAME
View logsdocker logs NAME
Follow logs livedocker logs -f NAME
Shell inside containerdocker exec -it NAME sh
List imagesdocker images
Show disk usagedocker system df

Images and tags

Images usually look like this:

nginx:latest
mariadb:10.11
fireflyiii/core:latest
postgres:16-alpine

latest is convenient but can change unexpectedly. For databases, prefer stable version tags like mariadb:10.11 or postgres:16-alpine.

Containers

A container is a running instance of an image.

docker run -d --name demo redis:7-alpine

Useful docker run flags:

FlagMeaning
-dDetached/background mode
--name NAMEFriendly container name
-p 8080:80Host port 8080 forwards to container port 80
-e KEY=valueSet environment variable
-v volume:/pathAttach storage
--restart unless-stoppedAuto-start after reboot unless manually stopped

Ports

Port syntax is:

host_port:container_port

Example:

docker run -d --name web -p 8080:80 nginx

This means:

Browser -> localhost:8080 -> container port 80

Use this when you want local-only access:

ports:
  - "127.0.0.1:8080:80"

Volumes and persistent data

Containers are disposable. Volumes are where data survives.

Named volume:

docker volume create mydata
docker run -d --name db -v mydata:/var/lib/mysql mariadb:10.11

Bind mount:

docker run -d --name app -v /home/user/config:/config some-image
Storage typeBest forProsCons
Named volumeDatabases and app dataDocker-managedHarder to browse manually
Bind mountConfig, imports, mediaEasy to edit and backupHost permissions matter

:::note Deleting a volume can delete your app/database data. Be careful with docker volume rm and especially docker compose down -v. :::

Networks

Docker Compose creates a private network for the services in a project. Containers can talk to each other using service names as hostnames.

In your Firefly III setup:

DB_HOST: db
DB_PORT: "3306"

db works because it is the Compose service name.

Docker Compose

Docker Compose defines multi-container applications in YAML.

Minimal example:

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    restart: unless-stopped

Daily Compose commands:

docker compose up -d
docker compose ps
docker compose logs -f
docker compose logs -f importer
docker compose restart importer
docker compose pull
docker compose up -d
docker compose down

Avoid this unless you intentionally want to delete volumes:

docker compose down -v

Environment variables and secrets

Inline variables:

services:
  app:
    image: example/app
    environment:
      TZ: "Australia/Melbourne"
      APP_URL: "http://localhost:8080"

Secrets in .env:

DB_PASSWORD='a-strong-password'
services:
  app:
    env_file:
      - .env

Never commit real .env files to a public repository.

Logs and debugging

Start here:

docker compose ps
docker compose logs -f SERVICE

Enter a container:

docker exec -it firefly-iii sh

Check environment variables:

docker exec firefly-importer env

Common problems:

ErrorLikely causeFix
Port already allocatedSomething else uses the host portChange the left side of 8080:80
Permission deniedDocker group or file permission issueCheck user group or mounted folder permissions
Container exits immediatelyBad config, missing env var, app crashCheck logs
Cannot connect to DBWrong hostname/password/networkIn Compose use service name, e.g. db

Updates

cd ~/firefly-iii
docker compose pull
docker compose up -d

Backups

For databases, prefer application/database-level exports when available. For a raw named-volume backup:

docker run --rm \
  -v firefly-iii_firefly_iii_db:/volume \
  -v "$PWD":/backup \
  alpine \
  tar czf /backup/firefly-db-volume-backup.tar.gz -C /volume .

Security basics

Your Firefly III stack

ServicePurposeURL / Access
firefly-iiiMain finance apphttp://localhost:8080
importerCSV/data import toolhttp://localhost:8081
dbMariaDB databaseInternal only, hostname db

Useful commands:

cd ~/firefly-iii

docker compose ps

docker compose logs -f firefly-iii

docker compose logs -f importer

docker compose restart importer

Rule of thumb

If you understand images, containers, ports, volumes, networks, and Compose, you understand most everyday Docker use.