My Hardware
| Machine | Intel N95 Mini PC |
| Processor | Intel N95 ยท 4 cores ยท 1700MHz |
| RAM | 16GB |
| System SSD | 476GB SSD |
| Storage HDD | 3.64TB HDD |
| Host OS | Windows 11 |
| Hypervisor | VMware Workstation |
| Server OS | Umbrel OS (VM) |
| Remote Access | Cloudflare Tunnel |
| VM RAM | 8GB allocated to Umbrel |
| VM Cores | 2 cores allocated to Umbrel |
| VM Storage | 2TB from HDD |
| VM Network | Bridged โ own IP on local network |
When you start self-hosting on Umbrel, the built-in App Store is fantastic for getting started. But eventually, you want to run applications that aren’t in the official store โ like Joplin Server, Grocy, or Recipe Buddy.
The most common advice you will find online is: “Just install Portainer from the Umbrel App Store and run your custom containers from there.”
I tried exactly that. And it completely broke my server’s stability. Here is why that happens and how I eventually fixed it.
The Problem: Two Masters, One Server
Umbrel is designed to be a “walled garden.” It relies on strict, hard-coded background scripts to manage its Docker environment. It assumes it has total control over ports, networks, and container restarts.
When you install Portainer inside Umbrel, you are introducing a second manager that tries to dictate rules in an environment Umbrel believes it owns.
In my setup, this caused a cascade of frustrating issues:
- The “Down” Environment: Portainer’s local environment would frequently and randomly show as “down” or disconnected in the web interface.
- Socket Permission Errors: Because Umbrel tightly controls system security, Portainer would frequently lose its access to the underlying Docker socket (
docker.sock). - Constant Manual Intervention: To get my custom apps working again, I had to constantly SSH into the server to manually fix the socket permissions or force-restart the Portainer services. It completely defeated the purpose of a reliable, automated home server.
The Solution: The Decoupling Method
I realized that if I wanted a stable system, I couldn’t have two managers fighting over the same Docker environment. The fix wasn’t to tweak Portainer โ the fix was to remove it entirely and decouple my custom apps from Umbrel’s ecosystem.
The strategy: Keep Umbrel apps inside Umbrel. Run custom apps completely independently.
How to Implement the Fix
Step 1 โ Uninstall Portainer
Remove it entirely from the Umbrel App Store to stop the background conflicts.
Step 2 โ Create isolated directories
Instead of putting custom apps inside /umbrel/ folders, create completely separate folders:
/home/umbrel/joplin-stack
/home/umbrel/grocy-stack
Step 3 โ Joplin Server docker-compose.yml
Place this inside /home/umbrel/joplin-stack/docker-compose.yml:
services:
db:
image: postgres:15
container_name: joplin-db
volumes:
- /mnt/root/data/app-data/joplin/db:/var/lib/postgresql/data
ports:
- "5432:5432"
restart: unless-stopped
environment:
- POSTGRES_PASSWORD=your_secure_password
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
app:
image: joplin/server:latest
container_name: joplin-server
depends_on:
- db
ports:
- "22300:22300"
restart: unless-stopped
environment:
- APP_BASE_URL=https://joplin.yourdomain.com
- APP_PORT=22300
- DB_CLIENT=pg
- POSTGRES_PASSWORD=your_secure_password
- POSTGRES_DATABASE=joplin
- POSTGRES_USER=joplin
- POSTGRES_PORT=5432
- POSTGRES_HOST=db
- TZ=Asia/Kolkata
Step 4 โ Grocy + Recipe Buddy docker-compose.yml
Place this inside /home/umbrel/grocy-stack/docker-compose.yml:
services:
grocy:
image: lscr.io/linuxserver/grocy:latest
container_name: grocy
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Kolkata
- GROCY_CURRENCY=INR
- GROCY_CALENDAR_FIRST_DAY_OF_WEEK=1
volumes:
- /mnt/root/data/app-data/grocy:/config
ports:
- 9283:80
restart: unless-stopped
networks:
- grocy_network
recipe-buddy:
image: ghcr.io/georgegebbett/recipe-buddy:latest
container_name: recipe-buddy
depends_on:
- grocy
environment:
- GROCY_API_KEY=your_grocy_api_key_here
- GROCY_BASE_URL=http://grocy:80
- NEXTAUTH_SECRET=your_random_secret_here
- NEXTAUTH_URL=https://recipes.yourdomain.com
- NEXTAUTH_URL_INTERNAL=http://localhost:3000
- AUTH_TRUST_HOST=true
- TZ=Asia/Kolkata
volumes:
- /mnt/root/data/app-data/recipe-buddy:/home/node/app/data
ports:
- 3005:3000
restart: unless-stopped
networks:
- grocy_network
networks:
grocy_network:
name: grocy_network
Bonus: Recipe Buddy connects directly to Grocy via the internal Docker network (grocy_network) โ no external URL needed between them.
Step 5 โ Deploy via SSH
cd /home/umbrel/joplin-stack
sudo docker compose up -d
cd /home/umbrel/grocy-stack
sudo docker compose up -d
The restart: unless-stopped policy ensures all containers come back up automatically after a reboot.
Making It Accessible Remotely: Cloudflare Tunnel
Rather than opening ports on my router or managing SSL certificates manually, I use Cloudflare Tunnel (cloudflared) for secure remote access. This means:
- No open ports on my router
- SSL handled automatically by Cloudflare
- Each app gets its own subdomain
| Subdomain | Internal Port | App |
|---|---|---|
| joplin.yourdomain.com | :22300 | Joplin Server |
| grocy.yourdomain.com | :9283 | Grocy |
| recipes.yourdomain.com | :3005 | Recipe Buddy |
Cloudflare Tunnel setup deserves its own post โ I will cover it in detail separately.
What I Would Do Differently
If I were starting over, I would never install Portainer inside Umbrel. The decoupling method from day one would have saved me hours of troubleshooting. The key insight is simple:
Umbrel is a great app platform. Docker Compose is a great custom app platform. Keep them separate and both work perfectly.
Key Takeaways
- Never install Portainer inside Umbrel โ it conflicts with Umbrel’s Docker management
- Run custom apps in isolated directories using native Docker Compose
- Use
restart: unless-stoppedfor automatic recovery after reboots - Cloudflare Tunnel gives you secure remote access without opening router ports
- Umbrel and custom Docker apps can coexist happily โ just keep them completely separate
