Help Running your server Docker and apps
Install Docker and Docker Compose
Install Docker from its official repository, run an app from a compose file, and keep its ports from slipping past your firewall.
Docker runs each app in a container with everything it needs, so you don't install its language or libraries yourself. Docker Compose describes an app's containers in one file you can keep and rerun.
Install Docker#
Install it from Docker's own repository. The docker.io and podman-docker packages are older builds without the Compose plugin.
Ubuntu / Debian
Add Docker's signing key and repository. The same lines work on both systems:
sudo apt update && sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release && sudo curl -fsSL "https://download.docker.com/linux/$ID/gpg" -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$ID ${UBUNTU_CODENAME:-$VERSION_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.listInstall Docker and the Compose plugin. It starts straight away, and at every boot:
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginAlmaLinux / Rocky
Add Docker's repository:
sudo dnf install -y dnf-plugins-core && sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repoInstall Docker and the Compose plugin:
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginIf it complains about conflicts with podman or runc, remove those first with sudo dnf remove -y podman runc, then try again.
Start it now and at every boot:
sudo systemctl enable --now dockerCheck it works with a tiny test image:
sudo docker run --rm hello-worldRun docker without sudo
To use docker without typing sudo, add your user to the docker group, then log out and back in:
sudo usermod -aG docker alexStop logs filling the disk#
Docker keeps every line a container prints, forever, which can fill the disk in weeks. Keep a few small files per container instead:
sudo tee /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
EOFsudo systemctl restart dockerThis applies to containers created from now on. Recreate older ones to pick it up: docker compose up -d --force-recreate in their folder.
Run an app with Compose#
The example is Uptime Kuma, which tells you when your websites go down. Every compose file has the same shape. Give each app its own folder under /opt:
sudo mkdir -p /opt/uptime-kuma && cd /opt/uptime-kumaWrite its compose file:
sudo tee compose.yaml <<'EOF'
services:
uptime-kuma:
image: louislam/uptime-kuma:1
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- ./data:/app/data
EOF| Line | What it does |
|---|---|
image | What to run, and which version |
restart: unless-stopped | Brings it back after a crash or a reboot |
ports | Publishes port 3001, on 127.0.0.1 only (see the firewall, below) |
volumes | Keeps the data in ./data, so it survives the container being replaced |
Start it in the background:
sudo docker compose up -dThen, from the app's folder:
| Command | What it does |
|---|---|
sudo docker compose ps | Shows what's running |
sudo docker compose logs -f | Follows the log. Ctrl+C stops following, not the app |
sudo docker compose restart | Restarts the app |
sudo docker compose down | Stops and removes the containers. Data in ./data stays |
To reach it from outside with HTTPS, put Caddy in front, with reverse_proxy 127.0.0.1:3001: see Host a website with HTTPS using Caddy.
Update an app
From the app's folder. Your data in ./data stays:
sudo docker compose pull && sudo docker compose up -dThen clear out old images nothing uses:
sudo docker image pruneDocker and your firewall#
So "8080:80" is reachable from anywhere, whatever ufw status shows. To keep control:
- Bind to
127.0.0.1, as in the example, and put Caddy in front. The best default. - Don't publish what you don't need. Containers in one compose file reach each other by service name, so a database never needs
ports. - On a VPS, use the portal firewall, which Docker can't change: see Set up the firewall.
Check what's listening. 0.0.0.0 or [::] means from anywhere:
sudo ss -ltnpBack up your apps#
Back up each app's folder under /opt and you can rebuild it anywhere with docker compose up -d. Dump databases rather than copying their files. See Back up your server.
Still stuck? Open a ticket and say which guide you followed.