浪人
DE | EN
Claude Code as Homelab Assistant - Part 3: Deploying a New Service
tech

Claude Code as Homelab Assistant - Part 3: Deploying a New Service

Back to Blog
4 min read

Claude Code as Homelab Assistant - Part 3: Deploying a New Service

Introduction

In Part 1 we set up Claude Code and performed the first security audit. In Part 2, Claude Code found and fixed a bug. In Part 3, I’m showing the third use case: deploying a completely new service from scratch - compose file, Traefik integration, HTTPS, backup extension.

The service is Wallos - an open-source subscription tracker. Self-hosted instead of storing financial data somewhere in the cloud, with multi-currency support, categories, and notifications. Exactly right for someone who wants to keep track of monthly expenses without handing them over to a third party.

What particularly interested me about this run: our setup is non-trivial. Traefik as a reverse proxy with automatic wildcard certificate, DNS challenge via Hostinger, proxy_net as a shared network for all services. This is the kind of setup where you’d normally have to look up all the labels and network configurations yourself. Claude Code took over completely - and even solved errors that came up along the way.


Main Section

The Slash Command

/deploy-service

Claude Code asks for service name and URL. The response:

I want to install Wallos at wallos.home.maker-ronin.cloud. The project and documentation can be found here: https://wallosapp.com/

wallos-setup-1

What happened in the next 34 seconds:

  1. Visited wallosapp.com and read documentation
  2. Checked GitHub repo for the official compose file
  3. Read existing stack as reference - Manyfold, to understand Traefik labels and network configuration
  4. Queried Docker Hub for the current stable tag - 4.7.2 instead of :latest
  5. Created a complete deployment plan

The result was a clean plan with all details:

PropertyValue
Stack path/home/ronin/docker/wallos/
Subdomainwallos.home.maker-ronin.cloud
Imagebellamy/wallos:4.7.2

Volumes, environment variables, ports, network - everything listed before a single file was written.

Step 2 - Creating Files

After the first “OK”, Claude Code created the files on the server.

wallos-setup-2

Something interesting happened: the first attempt failed.

fish: Expected a string, but found a redirection
cat > /home/ronin/docker/wallos/docker-compose.yml << 'EOF'

The server runs Fish Shell instead of Bash - and Fish doesn’t support heredoc syntax. Claude Code recognized this immediately, without me needing to intervene:

“Fish shell - no heredoc. I’ll use tee instead.”

Second attempt with printf ... | tee - works. Files created, immediately verified by re-reading.

The finished compose file:

services:
  wallos:
    container_name: wallos
    image: bellamy/wallos:4.7.2
    environment:
      TZ: 'Europe/Vienna'
    volumes:
      - ./db:/var/www/html/db
      - ./logos:/var/www/html/images/uploads/logos
    restart: unless-stopped
    networks:
      - proxy_net
    security_opt:
      - no-new-privileges:true
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wallos.rule=Host(`wallos.home.maker-ronin.cloud`)"
      - "traefik.http.routers.wallos.entrypoints=websecure"
      - "traefik.http.routers.wallos.tls.certresolver=letsencrypt"
      - "traefik.http.services.wallos.loadbalancer.server.port=80"
networks:
  proxy_net:
    external: true

Everything correct - fixed tag, both volumes, proxy_net external, all Traefik labels complete, no-new-privileges:true as security best practice.

Step 3 - Start and Traefik Diagnostics

wallos-setup-3

docker compose up -d - container starts, healthy after a few seconds.

Then the URL test: HTTP code 000 - the route wasn’t active yet. Instead of just waiting, Claude Code investigated on its own:

  • Queried Traefik API if the route was known
  • Python JSON parsing failed - tried a different approach
  • docker network inspect proxy_net - Wallos is in the network
  • Queried Traefik from within - route found
"service": "wallos",
"rule": "Host(`wallos.home.maker-ronin.cloud`)",
"priority": 37

Route active. Second URL test: HTTP 302 - redirect to app. ✅

Step 4 - Backup

wallos-setup-4

Claude Code read the backup script and determined: Wallos uses bind mounts, not Docker volumes. The suggested entry for the backup script:

# Wallos data
log "Backing up Wallos data..."
restic backup \
    /home/ronin/docker/wallos/db \
    /home/ronin/docker/wallos/logos \
    --tag wallos \
    --verbose

I’ll add the entry to the script manually - this keeps control over the backup script with me.

Claude Code’s summary after 1 minute 5 seconds:

StepStatus
Image researched (bellamy/wallos:4.7.2)
Stack files created
Container started & healthy
Traefik route active, URL responds (302)
Backup extension documented

The Result

wallos-setup-5

https://wallos.home.maker-ronin.cloud - Wallos is running, HTTPS works.

The wildcard certificate *.home.maker-ronin.cloud applies automatically to every new subdomain - no extra ACME configuration, no separate DNS challenge for Wallos. That’s the advantage when Traefik is set up cleanly: every new service gets HTTPS automatically.

wallos-setup-6

After creating the admin account - Wallos is running, logged in, ready for the first subscriptions.

CLAUDE.md Grows

wallos-setup-7

After deployment, Claude Code itself identified two learnings and suggested updating CLAUDE.md:

Learning 1 - Fish Shell: The SSH session runs under Fish Shell. << 'EOF' heredoc syntax doesn’t work - Claude Code had to switch to printf. From now on, CLAUDE.md states:

“Shell is fish - for file writes use printf or tee instead of bash heredoc.”

Learning 2 - Traefik API: Port 8080 is not directly accessible via localhost:8080 - only within the Traefik container. The correct way:

docker exec traefik wget -q -O- http://localhost:8080/api/...

This is also now documented in CLAUDE.md.

This is perhaps the most subtle but important feature of this setup: the context improves with every session. What was an unexpected error today becomes familiar territory on the next deployment - Claude Code knows it because it’s in CLAUDE.md.

A small mishap on the side: On the first registration attempt, I didn’t note the password and couldn’t log in. Fix: delete the SQLite database, restart the container, register again. rm /home/ronin/docker/wallos/db/wallos.db && docker restart wallos - done in 30 seconds. Claude Code deploys the service, but you still need to create the admin account yourself. 😄


Conclusion

What impressed me most about this run is not that it worked - but how it handled errors. Fish Shell instead of Bash, Python JSON parsing errors, Traefik route not yet active - each time Claude Code recognized the problem, chose a different approach, and continued. No manual intervention, no explanation from me needed.

The most challenging aspect of this setup is the Traefik integration: wildcard certificate, DNS challenge, proxy_net, the right labels in the right combination. This is exactly the kind of configuration you’d have to look up each time for a new service or copy from an existing stack. Claude Code learned from the existing stacks and transferred it correctly - in 34 seconds of planning, 1 minute 5 seconds of execution.

From idea to running service with HTTPS in under 2 minutes of active work time.

What comes next: The concept can be taken further - regular automatic health checks as a cron job, weekly audits running quietly in the background, notifications on critical findings. The foundation is there. What becomes of it depends on how far you want to take it.

The repo: github.com/RoninRage/homelab-claude-public