Your Synology NAS Thinks It Started Your Containers. It Didn't.

Synology Docker web

TL;DR

Synology’s SYNO.Docker.Container_1_start API hits error 500 under memory pressure and doesn’t retry. Your containers stay down until you notice. Set restart: unless-stopped at the Docker daemon level to bypass DSM entirely.

Synology’s Auto-Start Is Fundamentally Broken

Every Synology NAS with Container Manager has an auto-start mechanism. It calls SYNO.Docker.Container_1_start for each container on boot. Sounds fine until you look at what actually happens:

  1. DSM boots and fires container start calls
  2. Under memory pressure, the API returns {"success": false, "error": {"code": 500}} with the message “Resource temporarily unavailable”
  3. DSM does not retry
  4. Your containers stay stopped
  5. You don’t get notified

This means every power outage, DSM update, or unexpected reboot leaves your entire stack down. You find out when Sonarr hasn’t grabbed anything in three days.

The fix is embarrassingly simple. In every docker-compose.yml:

restart: unless-stopped

This operates at the Docker daemon level, completely bypassing Synology’s broken API layer. The daemon handles retries, backoff, and health checks natively. DSM’s auto-start becomes irrelevant.

Exit Codes Tell You Everything

When containers die on Synology, the exit code is your forensic trail:

  • Exit 0 — Clean shutdown. Normal.
  • Exit 137 — SIGKILL. The kernel OOM killer or Synology’s resource manager terminated the process. The container didn’t choose to stop. On a memory-constrained NAS, this is almost always the resource manager preemptively killing containers before the system locks up.
  • Exit 143 — SIGTERM. Clean shutdown requested and honored. This is what you see on docker stop or DSM shutdown.

If you’re seeing 137s on a NAS with 4 GB of RAM running 20+ containers, you don’t have a Docker problem. You have a physics problem.

NZB Obfuscation: Hash-Named Files Are the Video

Usenet uploaders obfuscate filenames to dodge DMCA takedowns. Instead of Invincible.S04E01.1080p.mkv, you get a folder full of files named a8f3e2d1b4c7.nzb.whatever. SABnzbd’s deobfuscation is supposed to rename these automatically. Sometimes it silently fails.

The fix when it does:

  1. Find the largest file in each episode folder — it’s the video
  2. Verify the Matroska header: first four bytes should be 1a 45 df a3
  3. Rename to .mkv
  4. Delete the par2/nfo/txt artifacts
  5. Flatten the subfolder structure so Sonarr can match

You can check the header with xxd -l 4 <file>. If you see 1a45 dfa3, that’s a valid Matroska container regardless of what the filename says.

4 GB + 23 Containers = Swap Death Spiral

My DS920+ has 4 GB of RAM. At peak, it was running 23 Docker containers. The math:

  • 3.7 GB total usable
  • 23 containers consumed enough that the system was using 1.9 GB of swap
  • Every container start/stop triggered page faults
  • Page faults stalled other containers
  • Stalled containers got killed by the resource manager (exit 137)
  • Killed containers restarted (if you were lucky enough to have restart policies)
  • Restarts consumed more memory
  • Repeat

The answer isn’t just restart policies. It’s reducing the container count to something the hardware can actually sustain.

The Cleanup: 23 to 10

After auditing every container, I cut the stack from 23 to 10:

Kept (core functionality): Sonarr, Prowlarr, Readarr, SABnzbd, Seerr, Recyclarr, Calibre-Web, Komga, Kavita, Audiobookshelf

Removed (13 containers): Whisparr (unused), Tautulli (Plex analytics I never check), Homepage (replaced by bythewei.dev), nas-node-exporter + 6 exportarrs (monitoring overhead exceeded value), libraryofbabel-grafana + libraryofbabel-prometheus (moved monitoring to Mac mini), synology_docviewer x2 (Synology system containers, not needed)

Memory freed: 2.4 GB used down to 1.8 GB. Available memory jumped from 839 MB to 1.6 GB. Swap dropped to near zero. No more exit 137s.

Practical Takeaways

  1. Never trust DSM’s auto-start. Set restart: unless-stopped on every container.
  2. Check exit codes when containers die. 137 means something killed them; 143 means they shut down cleanly.
  3. Monitor swap on 4 GB NAS boxes. If swap exceeds 500 MB, you’re running too many containers.
  4. SABnzbd deobfuscation fails silently. When it does, the largest file is the video. Check the magic bytes.
  5. Sonarr path case sensitivity matters. TVDB says “Invincible” but your filesystem says “INVINCIBLE”. Sonarr won’t find episodes until the paths match.

The Developer’s Perspective

Synology sells the DS920+ as a Docker-capable NAS. And it is — for maybe 8-12 containers, depending on how heavy they are. But DSM’s container management layer is a thin wrapper that fails silently under exactly the conditions you’d expect on a memory-constrained appliance.

The irony is that Docker itself handles all of this gracefully. Restart policies, health checks, resource limits — it’s all there at the daemon level. Synology’s API layer just gets in the way.

This session started as “check if Seerr is running.” It ended as a full infrastructure audit because one broken abstraction layer had been silently degrading everything underneath it. The lesson, as always: if your tooling can fail silently, it will fail silently, and you’ll find out at the worst possible time.