Back to all posts

Building a Zero Trust Home Server with Raspberry Pi, Cloudflare, and Tailscale

April 3, 2025
Building a Zero Trust Home Server with Raspberry Pi, Cloudflare, and Tailscale

In today's digital landscape, running your own private infrastructure is becoming increasingly popular. With a simple Raspberry Pi, you can self-host your own media, files, ad blocker, automation workflows, and more right from home, while maintaining complete control over your data.

This guide will help you understand how to set up a secure and accessible home server using zero trust principles, with no open ports on your home router.


Why Build a Zero Trust Home Server?

  • Complete Digital Privacy: Keep your data local and away from big tech companies
  • Enhanced Security: Access services without opening ports on your router
  • Centralised Control: Host your own media, files, dashboards, and automation tools
  • Accessible From Anywhere: Use secure tunnelling to access your services globally

What You Can Self-Host Securely

Here are some powerful services you can run on your Raspberry Pi:

Use Case Service What It Does Resource Requirements
Ad Blocking AdGuard Home / Pi-hole Network-wide ad and tracker blocking Low: 100MB RAM, minimal CPU
Zero Trust Access Tailscale / Cloudflare Tunnel Secure remote access without port forwarding Low: 200MB RAM, minimal CPU
Firewall & Protection UFW / Fail2Ban Secure your server from unwanted access Very Low: System level
Media Streaming Jellyfin Host your own Netflix-like streaming platform Medium-High: 1-2GB RAM, moderate CPU
Personal Cloud Storage Nextcloud Self-hosted alternative to Dropbox/Google Drive Medium: 1-2GB RAM, moderate CPU
Smart Home Home Assistant Smart home automation hub Medium: 1GB RAM, moderate CPU
Service Monitoring Uptime Kuma Monitor your services' health Low: 200-500MB RAM, low CPU
Password Management Vaultwarden Self-hosted Bitwarden-compatible password manager Low: 500MB RAM, minimal CPU
Docker Management Portainer Graphical interface to manage Docker containers Low: 500MB RAM, minimal CPU
Workflow Automation n8n Create powerful automation workflows Medium: 1GB RAM, moderate CPU
RSS Aggregator FreshRSS Track news and updates from your favorite sites Low: 200MB RAM, minimal CPU
Document Management Paperless-ngx Scan, store, and search your documents Medium: 1GB RAM, moderate CPU

Blog image Example Homer dashboard showing various self-hosted services

Real-World Performance Expectations on Raspberry Pi 4 (4GB)

  • Jellyfin: 1-2 direct play streams OR 1 1080p transcode
  • Nextcloud: Comfortable file syncing for 3-5 users
  • AdGuard + Tailscale + Uptime Kuma: Can run simultaneously with minimal impact
  • Storage needs: Start with 128GB SSD for OS + Docker, external HDD for media/backups

Setting Up Your Raspberry Pi

Hardware Requirements

For a reliable zero trust home server, you'll need:

  • Raspberry Pi 4 (4GB or 8GB recommended)
  • USB SSD (128GB+ recommended) instead of microSD for reliability
  • Official Power Supply (3A for Pi 4)
  • Case with cooling (like the Argon ONE M.2 or Flirc case)
  • Ethernet connection (strongly recommended for stability)

Blog image Raspberry Pi 4 with SSD and cooling case for optimal home server performance

Step 1: Install Raspberry Pi OS

  1. Download and Install Raspberry Pi Imager:

  2. Configure with Raspberry Pi Imager:

    • Open the Raspberry Pi Imager application
    • Click "Choose device" and select your Raspberry Pi model
    • Click "Choose OS" and select Raspberry Pi OS Lite (64-bit) for a headless server
    • Click "Choose storage" and select your SSD (connected via USB adapter)
  3. Configure Advanced Options:

    • Press Ctrl+Shift+X to open advanced options
    • Set a hostname (e.g., homeserver)
    • Enable SSH and configure an SSH key for passwordless login
    • Configure your WiFi (if not using Ethernet)
    • Set locale settings
    • Click Save and then Write
  4. Insert the SSD into your Raspberry Pi and power it on

Step 2: Initial Configuration

Connect to your Raspberry Pi via SSH:

            ssh username@homeserver.local
            
          

Update your system:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo apt update && "hljs-string">"hljs-built_in">"hljs-built_in">sudo apt full-upgrade -y
            
          

Set a static IP address (recommended):

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo nano /etc/dhcpcd.conf
            
          

Add these lines, customizing for your network:

          interface eth0
static ip_address=192.168.1.100/24
static routers=192.168.1.1
static domain_name_servers=1.1.1.1 1.0.0.1
          
        

Reboot to apply changes:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo reboot
            
          

Step 3: Security Hardening

Remove Password Authentication for SSH

If you didn't set up SSH keys during installation:

            "hljs-string">"hljs-comment"># On your "hljs-built_in">local machine
ssh-keygen -t ed25519 -C "hljs-string">"hljs-string">"hljs-string">"your_email@example.com"
ssh-copy-id username@your-pi-ip-address
            
          

Then disable password authentication:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo nano /etc/ssh/sshd_config
            
          

Find and modify these lines:

          PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
          
        

Restart SSH service:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo systemctl restart sshd
            
          

Set Up Basic Firewall

Install and configure UFW:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo apt install ufw
"hljs-string">"hljs-built_in">"hljs-built_in">sudo ufw default deny incoming
"hljs-string">"hljs-built_in">"hljs-built_in">sudo ufw default allow outgoing
"hljs-string">"hljs-built_in">"hljs-built_in">sudo ufw allow ssh
"hljs-string">"hljs-built_in">"hljs-built_in">sudo ufw "hljs-string">"hljs-built_in">"hljs-built_in">enable
            
          

Install Fail2Ban to Protect from Brute Force Attacks

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo apt install fail2ban
"hljs-string">"hljs-built_in">"hljs-built_in">sudo "hljs-string">"hljs-built_in">"hljs-built_in">cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
"hljs-string">"hljs-built_in">"hljs-built_in">sudo systemctl "hljs-string">"hljs-built_in">"hljs-built_in">enable fail2ban
"hljs-string">"hljs-built_in">"hljs-built_in">sudo systemctl start fail2ban
            
          

Configure a custom SSH jail:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo nano /etc/fail2ban/jail.local
            
          

Add/modify the SSH section:

          [sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400  # 24 hours
          
        

Restart Fail2Ban:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo systemctl restart fail2ban
            
          

Setting Up Docker and Portainer

Blog image Portainer dashboard showing running containers and resource usage

Docker allows you to run multiple services in isolated containers.

Install Docker and Docker Compose

            curl -fsSL https://get.docker.com | sh
"hljs-string">"hljs-built_in">"hljs-built_in">sudo usermod -aG docker "hljs-string">"hljs-variable">"hljs-variable">$USER
"hljs-string">"hljs-built_in">"hljs-built_in">sudo apt install -y docker-compose-plugin
            
          

Log out and log back in for group changes to take effect:

            "hljs-string">"hljs-built_in">"hljs-built_in">exit
"hljs-string">"hljs-comment"># Reconnect via SSH
            
          

Create Directory Structure

            "hljs-string">"hljs-built_in">"hljs-built_in">mkdir -p ~/docker/{compose,configs,data}
            
          

Install Portainer for Docker Management

Create a docker-compose file for Portainer:

            nano ~/docker/compose/portainer.yml
            
          

Add the following content:

            version: '3'
services:
  portainer:
    container_name: portainer
    image: portainer/portainer-ce:latest
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ~/docker/data/portainer:/data
    ports:
      - 9000:9000
            
          

Start Portainer:

            "hljs-string">"hljs-built_in">"hljs-built_in">cd ~/docker/compose
docker compose -f portainer.yml up -d
            
          

You can now access Portainer at http://your-pi-ip:9000 to set up your admin account.


Setting Up AdGuard Home In Detail

Blog image AdGuard Home dashboard showing blocked requests and filtering statistics

AdGuard Home is a powerful network-wide ad blocker and DNS server. Here's how to set it up and configure it properly.

Initial Setup

First Create and deploy the docker file

            version: '3'
services:
  # Network-wide ad blocking
  adguard:
    container_name: adguard
    image: adguard/adguardhome:latest
    restart: unless-stopped
    volumes:
      - ~/docker/configs/adguard:/opt/adguardhome/conf
      - ~/docker/data/adguard:/opt/adguardhome/work
    ports:
      - 3000:3000  # Admin Panel
      - 53:53/tcp  # DNS
      - 53:53/udp  # DNS
      - 784:784/udp # DNS-over-QUIC
      - 853:853/tcp # DNS-over-TLS
      - 443:443/udp # DNS-over-HTTPS
    cap_add:
      - NET_ADMIN
    networks:
      - home_network
            
          

Then run the file and access it

          http://your-pi-ip:3000
          
        

Follow the setup wizard:

  1. Create an administrator account
  2. Configure network settings:
    • Choose the interfaces to listen on (typically all)
    • Keep default ports:
      • DNS: 53
      • Web interface: 3000

Common DNS Issues and Fixes

Before AdGuard can function correctly, make sure port 53 is available:

            "hljs-string">"hljs-comment"># Check "hljs-keyword">if port 53 is "hljs-keyword">in use
"hljs-string">"hljs-built_in">"hljs-built_in">sudo lsof -i :53
            
          

If systemd-resolved is using it, reconfigure it:

            "hljs-string">"hljs-comment"># Edit resolved configuration
"hljs-string">"hljs-built_in">"hljs-built_in">sudo nano /etc/systemd/resolved.conf
            
          

Add or modify these lines:

          DNSStubListener=no
          
        

Then restart the service:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo systemctl restart systemd-resolved
            
          

Configuring AdGuard Home

1. DNS Settings

In the AdGuard Home dashboard, go to Settings > DNS Settings:

  • Set upstream DNS servers (recommended):

    • Cloudflare: 1.1.1.1 and 1.0.0.1
    • Quad9: 9.9.9.9 and 149.112.112.112
  • Enable DNS-over-HTTPS/TLS (for security)

  • Enable blocking of domains from filters

2. Filtering

Go to Filters > DNS blocklists and add these recommended lists:

  • AdGuard DNS filter
  • AdAway Default Blocklist
  • Peter Lowe's Ad and tracking server list
  • Malicious URL Blocklist by Curben
  • NoCoin Filter List

3. Configuring Local DNS Records

To use .home.internal domain names for local services:

  1. Go to Settings > DNS rewrite
  2. Add entries for each service:
    • Domain name: jellyfin.home.internal
    • Answer: your-pi-ip
    • Repeat for other services

4. Client Configuration

Set your router to use AdGuard as the DNS server:

  1. Access your router's admin interface
  2. Find DHCP/DNS settings
  3. Set primary DNS to your Raspberry Pi's IP address
  4. Save changes

Alternatively, configure individual devices to use your Pi's IP as their DNS server.

5. Security Features

Enable these additional security features:

  • Safe Search: Forces safe search on Google, Bing, etc.
  • Parental Control: Optional content filtering
  • Safe Browsing: Blocks malicious domains

6. Statistics and Logs

AdGuard Home provides detailed statistics and logs:

  • View top blocked domains
  • Check query logs for troubleshooting
  • Monitor overall network activity

Using AdGuard with Tailscale

To use AdGuard as your DNS server while connected to Tailscale:

  1. In Tailscale admin console, set a DNS nameserver:

    • Go to DNS > Nameservers
    • Add your Raspberry Pi's Tailscale IP
  2. Configure split DNS (optional):

    • In Tailscale admin, set up split DNS for .home.internal domains
    • This allows resolving local domains when away from home

Setting Up Zero Trust Remote Access

Blog image

Method 1: Tailscale - VPN-Like Mesh Network

Tailscale creates a secure mesh network between your devices without opening ports.

Install Tailscale

            curl -fsSL https://tailscale.com/install.sh | sh
"hljs-string">"hljs-built_in">"hljs-built_in">sudo tailscale up
            
          

Follow the authentication link to connect your Raspberry Pi to your Tailscale account.

Configure Tailscale for Subnet Routing (Optional)

To access other devices on your home network through Tailscale:

            "hljs-string">"hljs-built_in">"hljs-built_in">sudo tailscale up --advertise-routes=192.168.1.0/24
            
          

Go to the Tailscale admin console and approve the subnet routes.

Setting Up ACLs and Policy

For enhanced security, set up access control policies in the Tailscale admin panel.

Example ACL policy:

            {
  "acls": [
    {
      "action": "accept",
      "users": ["user@example.com"],
      "ports": ["*:*"]
    }
  ]
}
            
          

Method 2: Cloudflare Tunnel with Docker Compose

Blog image Diagram showing how Cloudflare Tunnel provide secure remote access

Cloudflare Tunnel lets you expose services using a custom domain without opening ports. Running it in Docker keeps everything neatly containerized.

Prerequisites

  1. Registered domain on Cloudflare
  2. Cloudflare account

Setting Up Cloudflare Tunnel via Web UI Docker Compose

The Cloudflare Tunnel can also be set up directly from the Cloudflare Zero Trust dashboard, which many users find more convenient:

  1. Log in to your Cloudflare account and navigate to Zero Trust > Access > Tunnels

  2. Click Create a tunnel and give it a name (e.g., "Home Server")

  3. You'll be provided with a tunnel token. Create a docker-compose file for Cloudflare:

            nano ~/docker/compose/cloudflare.yml
            
          

Add the following content:

            version: "3.8"
services:
  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    container_name: flaresolverr
    environment:
      - LOG_LEVEL=info
      - CAPTCHA_SOLVER=none
    ports:
      - 8191:8191
    restart: unless-stopped
            
          
  1. Start the Cloudflare tunnel:
            "hljs-string">"hljs-built_in">"hljs-built_in">cd ~/docker/compose
docker compose -f cloudflare.yml up -d
            
          
  1. Back in the Cloudflare dashboard, you'll be asked to configure public hostnames:

    • Click Add a public hostname
    • Enter the subdomain and domain (e.g., jellyfin.yourdomain.com)
    • For service, select "HTTP" and enter the local service address and port (e.g., jellyfin:8096)
    • Repeat for each service you want to expose
  2. Optional: Add authentication

    • In the Cloudflare dashboard, under the "Public Hostname" settings, you can enable "Zero Trust Policy"
    • Configure authentication methods (Google, GitHub, email one-time passwords, etc.)
    • Set up custom policies for who can access each service

Setting Up Essential Self-Hosted Services

Create a Complete Docker Compose Stack

Create a new docker-compose file:

            nano ~/docker/compose/services.yml
            
          

Add the following content:

            version: '3'
services:
  # Network-wide ad blocking
  adguard:
    container_name: adguard
    image: adguard/adguardhome:latest
    restart: unless-stopped
    volumes:
      - ~/docker/configs/adguard:/opt/adguardhome/conf
      - ~/docker/data/adguard:/opt/adguardhome/work
    ports:
      - 3000:3000  # Admin Panel
      - 53:53/tcp  # DNS
      - 53:53/udp  # DNS
      - 784:784/udp # DNS-over-QUIC
      - 853:853/tcp # DNS-over-TLS
      - 443:443/udp # DNS-over-HTTPS
    cap_add:
      - NET_ADMIN
    networks:
      - home_network

  # Service monitoring
  uptime-kuma:
    container_name: uptime-kuma
    image: louislam/uptime-kuma:latest
    restart: unless-stopped
    volumes:
      - ~/docker/data/uptime-kuma:/app/data
    ports:
      - 3001:3001
    networks:
      - home_network
  
  # Media server
  jellyfin:
    container_name: jellyfin
    image: jellyfin/jellyfin:latest
    restart: unless-stopped
    volumes:
      - ~/docker/configs/jellyfin:/config
      - /mnt/media:/media
    ports:
      - 8096:8096
    networks:
      - home_network
    environment:
      - JELLYFIN_PublishedServerUrl=jellyfin.yourdomain.com

  # Personal cloud storage
  nextcloud:
    container_name: nextcloud
    image: nextcloud:latest
    restart: unless-stopped
    volumes:
      - ~/docker/data/nextcloud:/var/www/html
    ports:
      - 8080:80
    depends_on:
      - nextcloud-db
    networks:
      - home_network
    environment:
      - MYSQL_HOST=nextcloud-db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=secure_password_here

  # Database for Nextcloud
  nextcloud-db:
    container_name: nextcloud-db
    image: mariadb:latest
    restart: unless-stopped
    volumes:
      - ~/docker/data/nextcloud-db:/var/lib/mysql
    networks:
      - home_network
    environment:
      - MYSQL_ROOT_PASSWORD=very_secure_root_password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=secure_password_here
      
  # Workflow automation
  n8n:
    container_name: n8n
    image: n8nio/n8n:latest
    restart: unless-stopped
    ports:
      - 5678:5678
    volumes:
      - ~/docker/data/n8n:/home/node/.n8n
    networks:
      - home_network
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=secure_password_here

  # Password manager
  vaultwarden:
    container_name: vaultwarden
    image: vaultwarden/server:latest
    restart: unless-stopped
    volumes:
      - ~/docker/data/vaultwarden:/data
    ports:
      - 8081:80
    networks:
      - home_network

networks:
  home_network:
    driver: bridge
            
          

Start all services:

            "hljs-string">"hljs-built_in">"hljs-built_in">cd ~/docker/compose
docker compose -f services.yml up -d
            
          

Setting Up a Homer Dashboard

Homer provides a clean, customizable dashboard for all your self-hosted services.

Create a docker-compose file for Homer:

            nano ~/docker/compose/homer.yml
            
          

Add the following content:

            version: '3'
services:
  homer:
    container_name: homer
    image: b4bz/homer:latest
    restart: unless-stopped
    volumes:
      - ~/docker/configs/homer:/www/assets
    ports:
      - 8082:8080
    networks:
      - home_network

networks:
  home_network:
    external: true
            
          

Start Homer:

            "hljs-string">"hljs-built_in">"hljs-built_in">cd ~/docker/compose
docker compose -f homer.yml up -d
            
          

Create a basic configuration:

            "hljs-string">"hljs-built_in">"hljs-built_in">mkdir -p ~/docker/configs/homer
nano ~/docker/configs/homer/config.yml
            
          

Add this sample configuration:

            title: "Home Server Dashboard"
subtitle: "Your Self-Hosted Services"
logo: "assets/icons/logo.png"
header: true
footer: '

Created with ❤️ with Homer

' # Links to services services: - name: "Media" icon: "fas fa-play-circle" items: - name: "Jellyfin" logo: "assets/icons/jellyfin.png" subtitle: "Media Server" tag: "media" url: "http://jellyfin.home.internal" target: "_blank" - name: "Storage" icon: "fas fa-database" items: - name: "Nextcloud" logo: "assets/icons/nextcloud.png" subtitle: "File Storage" tag: "storage" url: "http://nextcloud.home.internal" target: "_blank" - name: "System" icon: "fas fa-cogs" items: - name: "Portainer" logo: "assets/icons/portainer.png" subtitle: "Docker Management" tag: "system" url: "http://portainer.home.internal" target: "_blank" - name: "AdGuard Home" logo: "assets/icons/adguard.png" subtitle: "Ad Blocking" tag: "system" url: "http://adguard.home.internal" target: "_blank" - name: "Automation" icon: "fas fa-robot" items: - name: "n8n" logo: "assets/icons/n8n.png" subtitle: "Workflow Automation" tag: "automation" url: "http://n8n.home.internal" target: "_blank"

Create a directory for custom icons:

            "hljs-string">"hljs-built_in">"hljs-built_in">mkdir -p ~/docker/configs/homer/icons
            
          

You can download icons for your services and place them in this directory.

Setting Up Nginx Proxy Manager for Local Domain Names

To access your services with nice local URLs like portainer.home.internal:

            nano ~/docker/compose/nginx-proxy.yml
            
          

Add the following content:

            version: '3'
services:
  nginx-proxy-manager:
    container_name: nginx-proxy-manager
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
      - '81:81'
    volumes:
      - ~/docker/data/nginx-proxy-manager/data:/data
      - ~/docker/data/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
    networks:
      - home_network

networks:
  home_network:
    external: true
            
          

Start Nginx Proxy Manager:

            "hljs-string">"hljs-built_in">"hljs-built_in">cd ~/docker/compose
docker compose -f nginx-proxy.yml up -d
            
          

Access the admin interface at http://your-pi-ip:81 and set up proxy hosts for each service.

For each service, add a proxy host with:

  • Domain name: service.home.internal
  • Forward hostname/IP: The container name or IP
  • Forward port: The internal port of the service

To use .home.internal domains on your devices, either:

  1. Add entries to your hosts file on each device
  2. Configure AdGuard Home to handle local DNS resolution (recommended)

Accessing Your Services

On Your Local Network

Using nice local domain names:

  • Homer Dashboard: http://homer.home.internal
  • Portainer: http://portainer.home.internal
  • Jellyfin: http://jellyfin.home.internal
  • Nextcloud: http://nextcloud.home.internal
  • n8n: http://n8n.home.internal
  • AdGuard Home: http://adguard.home.internal

Or using IP address:

  • Homer Dashboard: http://your-pi-ip:8082
  • Portainer: http://your-pi-ip:9000
  • Jellyfin: http://your-pi-ip:8096
  • Nextcloud: http://your-pi-ip:8080
  • n8n: http://your-pi-ip:5678
  • AdGuard Home: http://your-pi-ip:3000

Remote Access with Tailscale

When away from home, connect to Tailscale and access services using the same local domain names or IP addresses.

Remote Access with Cloudflare Tunnel

Access through your custom domains from anywhere:

  • Jellyfin: https://jellyfin.yourdomain.com
  • Portainer: https://portainer.yourdomain.com
  • Nextcloud: https://nextcloud.yourdomain.com
  • n8n: https://n8n.yourdomain.com
  • Homer Dashboard: https://homer.yourdomain.com

Advanced Security Enhancements

Set Up Service-Specific Networks

Modify your docker-compose file to use specific networks for different types of services:

            networks:
  frontend_network:
    driver: bridge
  backend_network:
    driver: bridge
  database_network:
    driver: bridge
            
          

Then assign services to appropriate networks:

            jellyfin:
  networks:
    - frontend_network
    
nextcloud:
  networks:
    - frontend_network
    - backend_network
    
nextcloud-db:
  networks:
    - database_network
    - backend_network
            
          

Container Hardening

Add security constraints to your containers:

            yourservice:
  security_opt:
    - no-new-privileges:true
  read_only: true
  tmpfs:
    - /tmp
  restart: unless-stopped
            
          

Implement Traefik as a Reverse Proxy (Optional)

For more advanced configurations, implement Traefik to handle routing and SSL:

            traefik:
  container_name: traefik
  image: traefik:latest
  restart: unless-stopped
  ports:
    - 80:80
    - 443:443
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
    - ~/docker/configs/traefik:/etc/traefik
  command:
    - --providers.docker=true
    - --providers.docker.exposedbydefault=false
    - --entrypoints.web.address=:80
    - --entrypoints.websecure.address=:443
    - --certificatesresolvers.myresolver.acme.tlschallenge=true
    - --certificatesresolvers.myresolver.acme.email=your@email.com
    - --certificatesresolvers.myresolver.acme.storage=/etc/traefik/acme.json
            
          

Troubleshooting Common Issues

Network Connectivity Issues

Problem Possible Solutions
Can't SSH into server • Check IP address is correct
• Verify hostname resolution works
• Ensure SSH service is running
• Check firewall settings
Can't access web UIs • Verify correct ports are open in UFW
• Check Docker container is running
• Ensure service is bound to correct network interface
DNS not working with AdGuard • Check port 53 is not in use by systemd-resolved
• Verify network configuration points to AdGuard
• Check AdGuard logs for errors
• Try sudo systemctl stop systemd-resolved

Docker Issues

Problem Possible Solutions
Container won't start • Check logs: docker logs container_name
• Verify port conflicts: netstat -tulpn
• Check volume permissions
Permission errors • Check UID/GID mappings
• Fix permissions: chown -R user:group /path/to/volume
Resource limitations • Check resource usage: docker stats
• Add memory limits to containers
• Monitor with htop

Cloudflare Tunnel Issues

Problem Possible Solutions
Tunnel not connecting • Check cloudflared logs: sudo journalctl -u cloudflared
• Verify credentials file exists
• Ensure tunnel ID matches in config
Cannot access services • Check DNS records in Cloudflare dashboard
• Verify service is running on specified port
• Ensure your Access policies are configured correctly

Maintenance Checklist

To keep your home server running smoothly, perform these maintenance tasks regularly:

Weekly Tasks

  • Check disk space: df -h
  • Update containers: docker compose pull && docker compose up -d
  • Review logs for errors: docker logs --since 24h container_name

Monthly Tasks

  • Update host OS: sudo apt update && sudo apt upgrade -y
  • Check for unused containers/images: docker system prune
  • Review backup integrity
  • Check UPS battery status (if applicable)

Quarterly Tasks

  • Change passwords for critical services
  • Review port forwarding/firewall rules
  • Check hardware (dust, connections, etc.)
  • Update documentation of your setup

Community Resources

Get help and inspiration from these community resources:

Forums & Communities

Discord Servers

YouTube Channels


What's Next?

You now have a solid foundation for running your own secure private cloud using zero trust principles.

Here are some advanced projects to tackle next:

Advanced Projects

  • Automated Backups: Set up Restic or Duplicati to automatically backup important data
  • Analytics: Monitor your network with InfluxDB + Grafana for beautiful dashboards
  • Home Automation: Connect Home Assistant to your lights, sensors, and more
  • CI/CD Pipeline: Set up Gitea + Drone CI for your personal development projects
  • Extended Storage: Build a proper NAS with TrueNAS or Unraid

Final Thoughts

Your zero trust home server is more than just a tech project—it's a statement about data ownership and privacy. With Cloudflare Tunnel and Tailscale, you can access your services securely from anywhere without compromising your home network security.

Last updated: April 2025

Connect with Me

I'm always interested in connecting with fellow developers and tech enthusiasts. Feel free to reach out if you have questions or just want to chat about tech!