Between its massive documentation, easy-to-use Compose facility, and compatibility with thousands of first and third-party images, Docker is the best container runtime for newcomers to the self-hosting ecosystem. But when you’re a complete beginner, Docker’s quirks can catch you off-guard, and if you’re not careful, you can end up making a bunch of mistakes while spinning up new containers for your tinkering adventures.

Deploying containers with root privileges

Dockers supports rootless operation

When you install Docker Engine on a new machine, you’ll have to use sudo privileges when performing any actions that require this container runtime. Otherwise, the terminal will display an error because your user account doesn’t have the right permissions to connect to the root-only Docker daemon. When you’re a beginner, you might be tempted to grant sudo access to your Docker commands to circumvent this problem, but doing so makes the host more vulnerable to privilege escalation and container escape problems.

Since Docker supports rootless operations, you can manage your arsenal of self-hosted applications without requiring administrator-level access. The dockerd-rootless-setuptool.sh script makes it easy to enable rootless mode, and the only trade-off is that you won’t be able to expose privileged ports (anything below port 1024) without extra commands. Heck, I recommend enabling rootless mode as soon as you install this container runtime on your home server.

Causing failed deployments by mapping the same host port to multiple containers

Just run docker ps before spinning up an app

Whether you rely on docker run commands or use the simple Compose facility to deploy your containers, you’ve definitely come across port mappings. Essentially, it’s a process that connects the physical ports on your host machine with the ones that exist inside a container. The problem? You can have the same port numbers on the container side, but you’ll have to map them to different ports on the Docker server. But when you’re a beginner, it’s easy to get confused about which side corresponds to the host or container, and you’ll probably end up with a failed deployment if you aren’t careful.

For reference, the number on the left of the colon (:) represents the host port, while the number to its right points to the port on the container’s end. If I don’t have an instance of Portainer running on my Docker servers, I run the docker ps command to confirm whether the host port I wish to connect with a new container isn’t hogged by an old app. In case it’s already in use, I simply edit the value before the colon and access the container’s web UI with the newly-assigned port number.

Not creating persistent volumes for essential services

Or forgetting to back them up afterwards

If you’ve got a random container without bind mounts, all the data you’ve written to it will get lost the moment you shut it down. This can be a huge problem for databases, archive management tools, backup services, and practically any container where you want the data to remain even after a restart. That’s why you’re supposed to create bind mounts or persistent volumes for essential services with the --volume argument followed by a directory path for its persistent storage.

I’ve also noticed newcomers make another atrocious mistake with their bind mounts. Home servers, and by extension, Docker containers, are pretty experimental, and it’s easy to lose all your data with a single mistake. As such, you’ll want to back up the storage volumes for essential containers, or risk making your painstakingly assembled app stack vulnerable to botched experiments.

Leaving unused volumes when removing containers

Unless you wanted to leave them behind

Remember how I said bind mounts ensure your data remains on the host even when the container is no longer operational? Well, if you try to remove your self-hosted service with docker rm container_name when you’re done tinkering with it, its persistent volume will remain on your Docker host.

If you tend to run Docker containers inside VMs as I do, you can end up choking your host machine with the data left behind by old applications. Therefore, you’ll want to run the docker volume rm volume_name command or delete these storage directories manually via Portainer, Docker Desktop, or another GUI tool. While we’re on the subject, certain container images can hog hundreds of megabytes worth of space, so you might want to clear outdated, dangling images every once in a while by executing docker image prune.

Forgetting to update containers

Or worse, configuring automatic updates for mission-critical tools

While we’re on the subject of container images, most of the popular self-hosted apps often get new updates. But when you’re running them inside containers, you won’t be able to access the new features unless you update them with new images – and this process can get rather cumbersome if you try to update your entire stack manually.

If you’ve got Watchtower (or its forked versions), it can automate the container update process. Or, you can even configure the auto-update facility with What’s Up Docker, though I wouldn’t recommend doing so for important self-hosted services. That’s because faulty images aren’t uncommon, and since the automation platforms have no way to check whether the updated images work as expected, you could end up with a broken set of services if you’re particularly unlucky. Personally, I rely on WUD’s alert triggers to get notified about new container images before giving the A-OK myself, instead of relying on the automation platform.

A couple of more mistakes to avoid when you’re new to Docker

With how deep the Docker rabbit hole goes, this list is far from over. It’s fine to tinker with different containers, but you should avoid using unverified images from dubious sources. If you’re trying to experiment with demanding services on a low-end system, you’ll want to limit the resource consumption of your container stack manually or deal with an unresponsive server.

Docker Swarm’s high-availability provisions can sound tempting, and truthfully, it’s a neat orchestration platform – only if you’ve got the right number of container-hosting nodes. You could technically run a Swarm setup with just two nodes, but it involves a couple of workarounds, and I’d recommend going with at least three of them to avoid dealing with quorum issues.

👁 Accessing a Docker folder
5 Docker Compose tricks that made my home server more reliable

A collection of tips and tricks that leveled up my Docker Compose game