Setting up a homelab server is straightforward. Install a base operating system, choose a Docker tool like Portainer, get the Compose file for a service, and deploy it. Managing the server and its services is where it gets tedious. Fixing an issue isn’t the tough part; finding the root cause takes more time. For a simple issue, I had to open Portainer to find the container, SSH to read the logs, then switch to Uptime Kuma to check whether it was actually down, and Beszel to cross-check the server usage. Even if I got these things right, I had to put the pieces together to understand what the actual problem was.

I ran 17 different containers for my self-hosted services. Some of them have fairly complex setups. For example, Immich, Jellyfin, and Nextcloud were hosted on my server, but their media lived on my NAS. I always had to make sure the mounts were working correctly. The information was there, but scattered across separate interfaces. There were no links between them. Instead of adding another tool, I decided to connect Claude Code to my server using MCP. It didn’t replace my existing tools; it sat on top of all Docker containers. Instead of navigating through various interfaces, I could now ask what was wrong with a particular service in plain English.

Setting up the bridge

Easier than it looks

I was running Debian bare-metal on my homelab server. All services were deployed as separate Docker containers through Portainer. Jellyfin, Immich, and Nextcloud handled media, photos, and file services. Pi-hole, Cloudflared, and Omada Controller handled the network and DNS. Uptime Kuma, Beszel, and Speedtest Tracker covered monitoring and observability. The tools existed, and the data existed; the problem was getting answers from a single place.

The Claude Code setup took a few steps to get it up and running. I installed Claude Code on the server and registered docker-mcp to the Docker socket. I added a CLAUDE.md to set boundaries around sensitive containers. No new containers, no complex configuration — only a few straightforward steps. After the setup, it was the same Claude Code CLI I was familiar with. It felt like running commands, but it was plain English. The first thing I tried was “list all my running containers." The result was a clean table with all 17 containers, grouped by stacks.

I was comfortable with it since I was already familiar with SSH. It didn’t require learning a completely new tool. Most importantly, I didn’t need to navigate between interfaces for simple answers.

When you can just ask

Some things feel like cheating

I asked a simple question: “How many photos are in my Immich library?” Claude responded by execing into the Postgres container and ran a query directly. Initially, the query failed because of the wrong table name. It then analyzed its own error and the database structure to correct itself. It eventually returned data that was more accurate than the Immich app UI. The Immich app presented iPhone Live Photos as single images, but Claude counted the MOV sidecars of the live photos as separate assets.

A simple operation like restarting a container previously took multiple steps. I had to open Portainer, find the container, and then restart it. After connecting Claude Code, it took only a command in plain English. That said, not everything was fast. When I ran a multi-step question like ‘What image and version is Jellyfin running, and does it require an update?’ it took significantly longer to complete: 4 min 42 sec. This wasn’t really a trade-off; it was simply the nature of the question, since it required Claude to access the internet for up-to-date information.

It removed the friction of knowing where to look for information. Whether the process was slow or fast, didn't matter. I didn’t need to find the container that held Immich’s database, or what the SQL structure and the credentials to Postgres were. I asked the question, and it returned a complete answer.

It found problems I didn't ask about

My monitor missed them

I was asking a couple of routine questions about service availability in Uptime Kuma and my network speed history in Speedtest Tracker. These were informational questions, not troubleshooting.

My question was, "Based on the uptime-kuma logs, are all my monitored services up?” I expected a simple summary. Instead, it reported that Nextcloud’s external URL was returning 502 Bad Gateway errors. Uptime Kuma hadn’t sent any notifications, even though Nextcloud was down for nearly two hours. It didn’t flag the downtime, as the retry threshold wasn’t met.

My second question was, “Based on the speedtest-tracker logs, what’s my recent internet speed performance?” Claude couldn’t return the actual speed statistics, since the speed test history was stored inside the app and not in the logs. But it did report that there was an ongoing DNS resolution failure inside the container, which had been silently failing for two days. My internet was working fine, so I hadn’t thought to check the stats. But the issue was there, and Claude pointed it out.

These were two separate scenarios, but the pattern was similar. There were issues with my setup, but I hadn’t noticed them. In Uptime Kuma’s case, it didn’t meet the set threshold, so it didn’t trigger an alert. In Speedtest Tracker’s case, I simply hadn’t checked the logs. The setup wasn’t a replacement of Uptime Kuma or Speedtest Tracker; it made them more efficient by surfacing quiet errors.

What it still can't do

Not a Portainer replacement

If it could do everything, what was the catch? There were a few things it still couldn’t do. Claude Code was installed on my homelab server, meaning it only ran locally. I always had to access my server to ask questions. There was no remote access from the Claude web, desktop, or mobile apps. Accessing it required an SSH client. A web-based terminal with Cloudflare Tunnel could have been a workaround, but I didn’t opt for it.

Another limitation was its app-layer blindspot. While it could access all the Docker containers and it could run SQL queries, it couldn’t see anything that lived inside the application layer. For example, it couldn’t see the actual Immich or Jellyfin libraries. This wasn’t entirely a limitation but more of a boundary by design.

I also set a few precautions before asking any questions. I created a CLAUDE.md file to define boundaries around sensitive containers. I fully excluded Vaultwarden from Claude’s access and made the Omada controller container read-only. This wasn’t a hard technical lock but an instruction-based enforcement.

Claude Code is CLI-based, so there is no visual layer. If you prefer a GUI, Portainer is still a better choice for exploring containers, viewing configurations, and resource graphs. Claude sits between the SSH and the dashboards; it is not meant to replace either.

Same tools, completely different conversation

This setup wasn’t meant to replace Portainer or tools like Uptime Kuma or Speedtest Tracker. They were already the best at what they did. The tools were the same; the server was the same. It changed the way I interacted with them. The server and services were already capable. Claude surfaced the issues that were silently failing in the background. Instead of navigating through each tool, I could just ask. After a point, my homelab stopped being something I checked and started being something I could ask.

OS
Windows, macOS
Individual pricing
Free plan available; $17/month Pro plan

Claude is an AI assistant and a series of large language models developed and maintained by Anthropic.