Docker Basics Training Guide
A practical beginner-friendly guide to Docker, containers, images, volumes, networks, Compose, backups, and everyday self-hosting commands.
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
| Concept | Meaning | Analogy |
|---|---|---|
| Image | Read-only package/template for an app | App installer / blueprint |
| Container | Running instance of an image | The running app |
| Volume | Persistent Docker-managed storage | External data disk |
| Bind mount | Host folder mounted into a container | Shared folder |
| Network | Private virtual network between containers | Mini LAN inside Docker |
| Registry | Place where images are stored | App 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
| Task | Command |
|---|---|
| List running containers | docker ps |
| List all containers | docker ps -a |
| Start a container | docker start NAME |
| Stop a container | docker stop NAME |
| Restart a container | docker restart NAME |
| Remove a container | docker rm NAME |
| View logs | docker logs NAME |
| Follow logs live | docker logs -f NAME |
| Shell inside container | docker exec -it NAME sh |
| List images | docker images |
| Show disk usage | docker 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:
| Flag | Meaning |
|---|---|
-d | Detached/background mode |
--name NAME | Friendly container name |
-p 8080:80 | Host port 8080 forwards to container port 80 |
-e KEY=value | Set environment variable |
-v volume:/path | Attach storage |
--restart unless-stopped | Auto-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 type | Best for | Pros | Cons |
|---|---|---|---|
| Named volume | Databases and app data | Docker-managed | Harder to browse manually |
| Bind mount | Config, imports, media | Easy to edit and backup | Host 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:
| Error | Likely cause | Fix |
|---|---|---|
| Port already allocated | Something else uses the host port | Change the left side of 8080:80 |
| Permission denied | Docker group or file permission issue | Check user group or mounted folder permissions |
| Container exits immediately | Bad config, missing env var, app crash | Check logs |
| Cannot connect to DB | Wrong hostname/password/network | In 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
- Do not expose admin apps directly to the public internet unless you know what you are doing.
- Prefer LAN-only access, VPN, Tailscale, WireGuard, or a carefully configured reverse proxy.
- Use strong unique passwords.
- Keep images updated.
- Use official or reputable images.
- Pin database image versions.
- Store secrets in
.env, not public compose files.
Your Firefly III stack
| Service | Purpose | URL / Access |
|---|---|---|
firefly-iii | Main finance app | http://localhost:8080 |
importer | CSV/data import tool | http://localhost:8081 |
db | MariaDB database | Internal 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.