Cleaning up my Media Server: Complete Cleanup and Automated Updates with Watchtower

I recently found myself in a situation many self-hosters face: my media server was a mess. I had duplicate files everywhere, old TV shows I'd never watch again, and I was manually updating Docker containers whenever I remembered (which wasn't often). I decided it was time for a complete fresh start. Here's how I cleaned everything up and automated my updates.

The Problem I Faced

My media server had grown out of control. I thought I had hardlinks set up properly between my downloads and media folders, but when I started investigating, I discovered I'd been creating copies instead. This meant every movie and TV show was taking up twice the space it should. Additionally, I had accumulated years of content I no longer wanted, and updating my containers was a manual chore I kept putting off.

Part 1: Setting Up Automated Updates with Watchtower

First, I tackled the update problem. I was tired of manually checking for updates and running docker-compose pull for each service. I needed automation.

Adding Watchtower to My Stack

I added Watchtower to my docker-compose.yml. Here's what worked for me:

watchtower:
  container_name: watchtower
  image: containrrr/watchtower:latest
  restart: unless-stopped
  environment:
    - TZ=Europe/London  # My timezone
    - WATCHTOWER_CLEANUP=true
    - WATCHTOWER_INCLUDE_RESTARTING=true
    - WATCHTOWER_SCHEDULE=0 0 3 * * 1  # Monday 3 AM - when I'm definitely asleep
    - WATCHTOWER_TIMEOUT=60s
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
  command: jellyfin radarr sonarr prowlarr  # Only update my media containers
  networks:
    - default

The Email Notification Challenge

I wanted to know when updates happened, but I don't have an SMTP server. I use Apple's email service with my custom domain through Cloudflare. Setting this up was trickier than expected.

First, I needed an app-specific password from Apple:

  1. Went to appleid.apple.com
  2. Generated an app-specific password
  3. Created a secure file for it:
mkdir -p /opt/mediaserver/secrets
echo "my-apple-app-password" > /opt/mediaserver/secrets/apple_mail_password.txt
chmod 600 /opt/mediaserver/secrets/apple_mail_password.txt

Then I updated my Watchtower configuration:

environment:
  # ... other variables ...
  - WATCHTOWER_NOTIFICATIONS=email
  - [email protected]
  - [email protected]
  - WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.mail.me.com
  - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587
  - [email protected]  # This was the tricky part!
  - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD_FILE=/run/secrets/apple_mail_password
secrets:
  - apple_mail_password

The key discovery: I needed to use my actual Apple ID for authentication, not my custom domain email.

Testing Was Essential

I ran several tests before trusting it with my production containers:

docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e WATCHTOWER_NOTIFICATIONS=email \
  -e [email protected] \
  -e [email protected] \
  -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.mail.me.com \
  -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587 \
  -e [email protected] \
  -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=actual-app-password \
  containrrr/watchtower \
  --run-once \
  --monitor-only

Part 2: The Great Media Cleanup

With updates automated, I turned to my storage disaster. I had only 11 movies I actually wanted to keep, but my media folders were full of content I'd never watch again.

I always assumed my files were hardlinked. When I checked:

ls -la /data/media/movies/

I was shocked to see individual files with link counts of 1. My "hardlinks" were just copies! This explained why my storage was disappearing so quickly.

My Cleanup Strategy

I decided on a complete fresh start. Here's what I did:

  1. Created a list of movies to keep - I had 11 specific files I wanted to preserve
  2. Stopped all services to prevent any issues:
docker-compose stop qbittorrent radarr sonarr jellyfin
  1. Wrote a cleanup script because doing this manually would be error-prone
  2. Deleted everything except my chosen files

The scariest part was running rm -rf commands on my media. I triple-checked my keep list before executing.

Part 3: The Jellyfin Ghost Problem

After deleting all my files and restarting Jellyfin, I hit an unexpected issue: all the deleted shows still appeared in the interface! They couldn't play (obviously, the files were gone), but they cluttered my library.

Investigating the Problem

I realized Jellyfin was holding onto database entries for non-existent files. Simply rescanning the library wasn't enough.

My Solution: Direct Database Surgery

This felt risky, but I needed those entries gone:

# Accessed the Jellyfin container
docker exec -it jellyfin bash

# Installed SQLite (it wasn't included)
apt update && apt install -y sqlite3

# Found the right database
find /config -name "*.db" -type f

I discovered the database was at /config/data/data/library.db, not where I initially looked.

-- Connected to the database
sqlite3 /config/data/data/library.db

-- Found the ghost entries
SELECT Name, Path FROM TypedBaseItems WHERE Path LIKE '%/tv/%' LIMIT 10;

-- Took a deep breath and deleted them
DELETE FROM TypedBaseItems WHERE Path LIKE '%/tv/%';

After restarting Jellyfin, finally, success! My library showed only my 11 movies.

Lessons Learned

  1. Hardlinks aren't automatic - I should have verified this years ago
  2. Test everything - Especially before running deletion commands
  3. Databases remember everything - File deletion doesn't mean library cleanup
  4. Automation saves time - Watchtower now handles what I always forgot to do
  5. Document your setup - This blog post serves as my personal reference too

Current Status

My media server is now:

  • Clean: Only the content I actually want
  • Automated: Updates happen every Monday at 3 AM without my intervention
  • Monitored: I get emails when containers update
  • Documented: I know exactly how everything is configured

Moving Forward

I've learned to:

  • Enable hardlinks properly in Radarr/Sonarr (Settings → Media Management → Use Hardlinks)
  • Regularly review my content instead of hoarding
  • Trust automation but verify with logs
  • Keep better documentation of my setup

This cleanup was overdue, but I'm glad I finally did it. If you're facing similar issues, I hope my experience helps you avoid some of the pitfalls I encountered. Sometimes you need to burn it down and start fresh.

Read more