Docker Watchtower on a Hostperl VPS in 2026

Why Docker Watchtower fits a small VPS
Docker Watchtower updates running containers on a schedule, so you do not have to log in for every patch cycle. On a Hostperl VPS, that matters when you run a customer site, a staging stack, or a small internal app and want fewer manual restarts.
This tutorial walks you through the full setup, from the first SSH login to a working Watchtower install. You will check the firewall, create a Docker Compose file, verify logs, and keep a clear rollback path. If you are also deciding whether to run your app on a managed stack, a Hostperl VPS gives you the room to test this cleanly before you move production traffic.
If you are choosing a deployment style, the related guide on Docker Compose deployment on VPS is a useful companion. It covers the base app layout; this article adds automated updates on top.
Connect to the VPS and check the operating system
On your local computer:
ssh root@203.0.113.10203.0.113.10 is a reserved documentation example. Replace it with the public IP assigned to your Hostperl server. If your provider gives you a non-root login, use that first and keep the same server IP.
Once you are in, detect the OS before you install anything.
On the VPS as root:
cat /etc/os-releaseYou should see either Ubuntu/Debian or AlmaLinux/Rocky Linux. The next steps are split so you use the correct package manager and service names.
Prepare the server for Docker Watchtower
Start with a non-root admin, system updates, time sync, and swap if the VPS is small. That gives you a steadier host before you let containers auto-update.
Ubuntu and Debian
On the VPS as root:
apt update && apt -y upgradeThis refreshes package lists and installs current patches. Reboot now if the kernel was updated.
adduser deployCreate the deploy account when you want a normal admin login. Set a strong password when prompted.
usermod -aG sudo deployThis grants sudo access. Keep your root session open until the new login works.
apt -y install ca-certificates curl gnupg openssh-server chrony ufwThese packages provide HTTPS trust roots, package signing support, SSH, time sync, and a firewall. chrony is the current default time-sync choice on many installs.
systemctl enable --now chronyTime sync helps with logs and TLS checks.
AlmaLinux and Rocky Linux
On the VPS as root:
dnf -y updateInstall current patches first. Reboot if the kernel changed.
useradd -m -G wheel deployCreate the deploy user and add it to the sudo-capable wheel group.
passwd deploySet the initial password if you want password-based access. If you plan to use SSH keys only, you can lock it later.
dnf -y install ca-certificates curl gnupg2 openssh-server chrony firewalldThese provide the same core setup on RHEL-compatible systems.
systemctl enable --now chronyd firewalldEnable time sync and the firewall.
Create and test the non-root SSH login
Do not disable root until you verify the new account from a second terminal. That avoids lockout.
On your local computer:
ssh-keygen -t ed25519 -C "deploy@example.com"This creates a key pair on your workstation if you do not already have one.
ssh-copy-id deploy@203.0.113.10Replace the IP with your server’s public address. This copies your public key to the new account.
On the VPS as root:
mkdir -p /home/deploy/.ssh && chown -R deploy:deploy /home/deploy/.ssh && chmod 700 /home/deploy/.sshThis is the manual fallback if you need to place the key yourself.
touch /home/deploy/.ssh/authorized_keys && chown deploy:deploy /home/deploy/.ssh/authorized_keys && chmod 600 /home/deploy/.ssh/authorized_keysAfter the key is in place, open a second terminal and test the account.
On your local computer:
ssh deploy@203.0.113.10Then confirm sudo works.
On the VPS as the non-root sudo user:
sudo -vIf that succeeds, leave the root session open only for emergency recovery.
Install Docker Engine and Compose
Watchtower needs Docker running cleanly first. Use the official repository so you get current packages.
Ubuntu and Debian
On the VPS as root:
install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpgIf you are on Debian, replace ubuntu with debian in the Docker repository line below.
. /etc/os-release && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable" > /etc/apt/sources.list.d/docker.listapt update && apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginsystemctl enable --now dockerAlmaLinux and Rocky Linux
On the VPS as root:
dnf -y install dnf-plugins-corednf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repodnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginsystemctl enable --now dockerCheck the version before you continue.
On the VPS as the non-root sudo user:
docker --version && docker compose versionYou should see current Docker and Compose output. If you want the deploy user to run Docker without sudo, add it to the docker group and log in again.
On the VPS as root:
usermod -aG docker deployThen reconnect as deploy and confirm docker ps works.
Open the firewall before exposing the service
Watchtower itself does not need an inbound port, but Dockerized apps usually do. Allow SSH first, then the web ports you actually use.
Ubuntu and Debian with UFW
On the VPS as root:
ufw allow OpenSSHufw allow 80/tcpufw allow 443/tcpufw --force enableufw status verboseKeep SSH allowed before you enable the firewall. The status output should list OpenSSH and any HTTP ports you opened.
AlmaLinux and Rocky Linux with firewalld
On the VPS as root:
firewall-cmd --permanent --add-service=sshfirewall-cmd --permanent --add-service=httpfirewall-cmd --permanent --add-service=httpsfirewall-cmd --reloadfirewall-cmd --list-allOn SELinux-enabled hosts, leave it enforcing unless your app needs a specific policy change. Watchtower itself does not need a special SELinux exception.
Create the Watchtower stack
Use a dedicated directory so the container definition is easy to back up and inspect.
On the VPS as the non-root sudo user:
sudo mkdir -p /opt/myapp/watchtower && sudo chown -R deploy:deploy /opt/myappThis gives the deploy user ownership of the deployment files.
cd /opt/myapp/watchtower && pwdCreate the Compose file.
nano docker-compose.ymlPaste this file content, then save and exit with Ctrl+O, Enter, and Ctrl+X.
services:
watchtower:
image: containrrr/watchtower:1.7.1
container_name: watchtower
restart: unless-stopped
command: --interval 300 --cleanup --label-enable
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=Pacific/AucklandThis checks for updates every five minutes, removes old image layers, and only updates containers that carry the Watchtower label. Adjust TZ if your server uses another timezone.
Start the stack.
docker compose up -dThen confirm the container is running.
docker compose psLabel a container for automatic updates
Watchtower ignores unlabeled containers in this setup. That keeps control in your hands.
Here is a simple example app container you can adapt to your own service.
On the VPS as the non-root sudo user:
nano /opt/myapp/watchtower/docker-compose.ymlReplace the file with this example that adds a test app and a Watchtower label. Save and exit when done.
services:
app:
image: nginx:1.27-alpine
container_name: app
restart: unless-stopped
labels:
- com.centurylinklabs.watchtower.enable=true
ports:
- "8000:80"
watchtower:
image: containrrr/watchtower:1.7.1
container_name: watchtower
restart: unless-stopped
command: --interval 300 --cleanup --label-enable
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=Pacific/AucklandBring the stack back up.
docker compose up -dNow test the app from the server and from your computer.
On the VPS as the non-root sudo user:
curl -I http://127.0.0.1:8000On your local computer:
curl -I http://203.0.113.10:8000Replace the IP with your real server address. You should get an HTTP 200 or 304 response from Nginx.
Check logs, updates, and runtime behavior
Watchtower writes clear logs when it scans and updates containers. Read them before you trust it in production.
On the VPS as the non-root sudo user:
docker logs --tail 50 watchtowerLook for messages about scanned containers, skipped unlabeled containers, or successful image checks. If you see permission errors on the Docker socket, verify the user is in the docker group and re-login.
To simulate an update safely, change the image tag of the test app or run a container you control with a newer tag. Watchtower should pull the new image and recreate only the labeled container.
Check whether the container restarted cleanly.
docker ps --format 'table {{.Names}} {{.Status}} {{.Image}}'Make it survive a reboot
Docker restart policies cover the container side. You should also confirm the host services start on boot.
On the VPS as root:
systemctl is-enabled dockersystemctl is-enabled sshdOn Ubuntu and Debian, the SSH service name is usually ssh. On AlmaLinux and Rocky Linux, it is sshd. Check the one your OS uses.
After a controlled reboot, verify the stack comes back.
rebootThen reconnect and run:
docker compose -f /opt/myapp/watchtower/docker-compose.yml psTroubleshooting the common failures
Docker does not start: check the unit and the journal.
systemctl status docker --no-pagerjournalctl -u docker -n 50 --no-pagerIf the logs mention storage or cgroup issues, fix the underlying host problem before retrying.
Watchtower cannot read the Docker socket: confirm permissions and group membership.
id deployIf docker is missing from the groups list, run usermod -aG docker deploy as root and log out and back in.
Your app stops responding after an update: inspect the container logs and roll back to the previous image tag.
docker logs --tail 100 appdocker compose pull app && docker compose up -d appIf you pinned the last working tag in your Compose file, restore that tag and bring the service up again. That is the safest rollback path for a small VPS.
Final verification
Before you close the ticket or hand the server to a client, check the host, the containers, and the web endpoint.
On the VPS as the non-root sudo user:
docker compose -f /opt/myapp/watchtower/docker-compose.yml psdocker logs --tail 20 watchtowerss -tulpn | grep 8000On your local computer:
curl -I http://203.0.113.10:8000If you are using this for a client site, pair it with an app backup schedule and a restore test. The article on PostgreSQL backup and restore on a Hostperl VPS is useful if your stack depends on a database.
If you want a VPS that gives you room to test container updates without crowding production traffic, Hostperl can help. A Hostperl VPS is a practical fit for Docker-based sites, internal tools, and small client deployments.
For teams that need steadier resources or more headroom for several services, see dedicated server hosting as well.
FAQ
Does Watchtower update every container automatically?
Not with the setup above. It only updates containers that carry the Watchtower label, which is safer for production.
Can I use this on a fresh Hostperl VPS?
Yes. Start with the OS check, Docker install, firewall rules, and a labeled test container before you attach real services.
Will this work behind Nginx?
Yes. Watchtower updates containers underneath Nginx, so your reverse proxy usually stays in place. Just keep your app health checks in mind.
How do I stop an unwanted update?
Pin the working image tag in your Compose file, redeploy that tag, and confirm the container returns to the previous version.
Should I use it for every workload?
No. Use it for low-risk services first. For customer-facing apps, keep backups, a rollback tag, and a short maintenance window plan.
