Docker on Synology: A Practical Container Manager and Docker Compose Guide

By Eddie Power Oct 9, 2026 in Containers & Virtualization 6 min read
docker Synology NAS Docker Compose Containers

A Synology NAS makes a surprisingly good little container host: it's always on, it has plenty of storage, and DSM handles RAID, snapshots and backups for you. Since DSM 7.2, Docker comes as the Container Manager package, and its Project feature runs standard Docker Compose files. (On some newer DSM builds the package name has drifted back towards plain "Docker", so check Package Center for whichever one your model offers.)

This guide is the setup I'd recommend to anyone starting out: a tidy folder layout, permissions that don't break, a first Compose project, sensible ports, and an update and backup routine. I'll use Uptime Kuma as the example because it's small, useful and has a web UI.

Check your model first

Container Manager runs on most x86 "Plus" and "XS" models and on some ARM64 models. Budget "j" and value-series units often can't run it at all. Check your model's page on Synology's site or search for the package in Package Center. If it isn't listed, your NAS can't run it.

RAM matters more than CPU for typical home-lab containers. 2 GB is tight once DSM, Synology Photos and a few containers are running; 4 GB or more is comfortable.

Step 1: Create a docker shared folder

Installing Container Manager usually creates a shared folder called docker on your first volume. If not, create it in Control Panel > Shared Folder. Give each project its own subfolder:

/volume1/docker/
├── uptime-kuma/
│   ├── compose.yaml
│   └── data/
└── wiki/
    ├── compose.yaml
    ├── .env
    └── data/

Keeping the Compose file next to its data makes each app self-contained, easy to back up and easy to move to another machine.

Step 2: Work out PUID and PGID

The most common Synology container problem is permissions: the app inside the container runs as a user that can't write to the folder you mapped. Many images (especially LinuxServer.io ones) accept PUID and PGID variables so the container runs as a real DSM user.

Create a dedicated, non-admin DSM user for containers (for example dockerapps), give it read/write access to the docker share, then find its IDs over SSH:

id dockerapps
# uid=1027(dockerapps) gid=100(users) groups=100(users)

Images that don't support PUID/PGID usually document a fixed user ID instead. For those, give that UID ownership of the data folder once over SSH (for example sudo chown -R 1000:1000 /volume1/docker/app/data).

Step 3: Write the Compose file

Create /volume1/docker/uptime-kuma/compose.yaml. File Station works, but editing over SSH with vi or VS Code Remote is easier (see my Synology SSH key guide).

services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    restart: unless-stopped
    ports:
      - "127.0.0.1:3001:3001"
    volumes:
      - ./data:/app/data
    environment:
      - TZ=Australia/Melbourne

Three habits worth copying:

  • Pin a major version tag (:1) rather than :latest, so an update never silently jumps to a new major release with breaking changes.
  • Use relative paths (./data) so the project folder is portable.
  • Bind to 127.0.0.1 when the app will sit behind DSM's reverse proxy. It's then unreachable directly from the LAN, and only the proxy can reach it. Use "3001:3001" instead if you want LAN access by IP and port.

Step 4: Create the project in Container Manager

  1. Open Container Manager > Project > Create.
  2. Name it uptime-kuma and set the path to /docker/uptime-kuma.
  3. Choose Use existing docker-compose.yml (it detects compose.yaml), or paste the file into the editor.
  4. Skip the Web Station portal option for now; we'll use the reverse proxy instead.
  5. Click Done. Container Manager pulls the image and starts the stack.

The project page shows logs, lets you stop, start and rebuild the stack, and edit the YAML. Behind the scenes it's plain Docker Compose, so you can also manage it over SSH:

cd /volume1/docker/uptime-kuma
sudo docker compose ps
sudo docker compose logs -f --tail=50

On DSM, Docker commands need sudo because the Docker socket belongs to root. Don't add users to a docker group or loosen the socket permissions; that's equivalent to giving them root.

Step 5: Avoid port conflicts

DSM's own web server uses ports 80 and 443, and DSM itself uses 5000 and 5001. Don't map containers to those. Pick high ports (3000–9999 is fine, avoiding anything another package already uses) and check what's listening before you choose:

sudo netstat -tlnp | grep -E ':(3001|8080|8443) '

To give apps proper HTTPS names on port 443, put them behind DSM's reverse proxy. That whole process is covered in Synology reverse proxy with Let's Encrypt.

Step 6: Keep secrets out of the YAML

For apps that need database passwords or API keys, put them in a .env file beside compose.yaml and reference them:

# .env  (chmod 600, never commit to git)
DB_PASSWORD=change-me-to-a-long-random-string
    environment:
      - DB_PASSWORD=${DB_PASSWORD}

Generate strong values with openssl rand -base64 32. For a deeper look at secrets, named volumes and networks, read Docker in production: volumes, networks and Compose secrets.

Step 7: Updating containers

Container Manager can show when a newer image is available. The simplest manual routine over SSH:

cd /volume1/docker/uptime-kuma
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune -f

pull downloads newer images for your pinned tags, up -d recreates only the containers whose image changed, and prune removes the old images. Read the app's release notes before major-version jumps, and take a snapshot first (next step). Avoid auto-updaters that pull :latest overnight on anything you rely on.

Step 8: Snapshots and backups

This is where a Synology shines:

  • Snapshots: if your volume is Btrfs, install Snapshot Replication and schedule hourly or daily snapshots of the docker share. A bad update becomes a two-minute rollback. (Btrfs snapshots are copy-on-write, so they're nearly free until data changes.)
  • Backups: add the docker share to a Hyper Backup task that goes off the box, to a USB drive, another NAS or cloud storage. Snapshots on the same disks are not a backup.
  • Databases: for apps with a database container, stop the stack or use the database's own dump tool before backing up, so you never copy a half-written database file.

Troubleshooting

  • Container restarts in a loop: check sudo docker compose logs. "Permission denied" on a data path means PUID/PGID or folder ownership (Step 2).
  • "Port is already allocated": something else is on that port; pick another one (Step 5).
  • App works by IP but not through the proxy: the reverse proxy destination port is wrong, or the app needs WebSocket headers.
  • Container can't reach the internet: check the DSM firewall and that the container is on the default bridge or a user-defined network, not network_mode: none.

Next steps

Once one project works, the pattern repeats: a folder, a Compose file, a high port and a reverse proxy rule. If you want rootless containers with tighter isolation on a regular Linux server, have a look at Podman rootless containers.

Share this article

E
Eddie Power admin

Eddie Power is a full-stack web developer based in Frankston, Victoria, with more than a decade of experience building websites, Laravel and PHP applications and iOS apps. He self-hosts this blog on a Synology NAS and writes about Linux, security and self-hosting.

Comments (0)

No comments yet. Be the first to leave one!

Leave a Comment

Comments are moderated and will appear after approval.