My Homelab Journey: Step-by-Step Guide with Raspberry Pi - Part 2

Ayoub ToubaAyoub Touba
7 min read

Welcome back! After setting up Docker and Docker Compose in the first part, it’s time to move on to the fun stuff: Portainer, Nginx Proxy Manager (NPM), and AdGuard Home. These tools will take my homelab to the next level, helping me manage containers, secure services with SSL, and handle DNS issues like a pro. Let me walk you through what I did.

Portainer: Simplifying Docker Management

I love how Docker makes managing containers easy, but typing commands every time can get tedious. That’s where Portainer comes in! It’s a web-based tool that lets me manage Docker with just a few clicks.


Setting Up Portainer

First, let’s create a volume to store Portainer’s database:

docker volume create portainer_data

Next, download and install the Portainer Server container:

docker run -d \
  -p 8000:8000 \
  -p 9443:9443 \
  -p 9000:9000 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:2.21.4

Once done, open your browser and navigate to:

https://<your-pi-address-or-hostname>:9443

In my case, I used https://pifour.local:9000.


Setting Up Nginx Proxy Manager for SSL Certificates

After getting Portainer set up, I turned my attention to Nginx Proxy Manager (NPM). Why? Because I wanted to access my services with nice, clean URLs (like app.localdomain.com) and secure them with SSL certificates.


Why a Domain Name?

I bought a domain name specifically for local use. The domain is mapped to the Raspberry Pi’s local IP address. This setup allows me to generate SSL certificates and bypass potential DNS rebinding issues.

Why NPM?

Here’s why I’m loving NPM:

  • Custom Domains: No more memorizing IPs and ports.

  • SSL Made Easy: Let’s Encrypt certificates with a few clicks.

  • Simple UI: Setting up reverse proxies is super straightforward.

Installing Nginx Proxy Manager

We’ll create a stack from the Portainer dashboard:

  1. Go to Portainer Dashboard.

  2. Click "Add Stack."

  3. Add the docker-compose.yml content from Nginx Proxy Manager’s setup page. Here’s the content for reference:

services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'    # HTTP
      - '443:443'  # HTTPS
      - '81:81'    # Admin UI
    environment:
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "npm"
      DB_MYSQL_PASSWORD: "npm"
      DB_MYSQL_NAME: "npm"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    depends_on:
      - db

  db:
    image: 'yobasystems/alpine-mariadb:latest'
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 'npm'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'npm'
    volumes:
      - ./mysql:/var/lib/mysql

Note: The yobasystems/alpine-mariadb image is used here because it supports ARM devices like the Raspberry Pi.

After deploying the stack, visit: http://<your-pi-address-or-hostname>:81

Default Credentials:

  • Email: admin@example.com

  • Password: changeme

Update your details and password after logging in.


Configuring SSL and Fixing DNS Rebinding

One challenge I faced was DNS rebinding. This happens when trying to access local domains, and some routers block them for security reasons. To fix this and improve my network’s DNS, I installed AdGuard Home.


Setting Up AdGuard Home

AdGuard Home is fantastic for blocking ads and resolving DNS issues like rebinding protection.

Here’s how I set it up:

  1. Create a New Stack in Portainer
    Add a new stack with the following docker-compose.yml configuration:
services:
  adguardhome:
    image: adguard/adguardhome
    container_name: adguardhome
    restart: unless-stopped
    ports:
      - "8080:80/tcp"  # HTTP interface (use alternative ports to avoid conflicts)
      - "8443:443/tcp" # HTTPS interface (use alternative ports to avoid conflicts)
    volumes:
      - /data/adguard-home/work:/opt/adguardhome/work
      - /data/adguard-home/confdir:/opt/adguardhome/conf

Since Nginx Proxy Manager is already using ports 80 and 443, I mapped AdGuard Home to 8080 and 8443.

  1. Visit AdGuard’s Setup Page
    After deploying the stack, visit http://<your-pi-address-or-hostname>:8080 to complete the initial setup.

  2. Set AdGuard as Your Router’s DNS:
    Update your router’s DHCP settings to use AdGuard for DNS. For instance, with Freebox OS, you can easily configure the DNS settings in the router's admin panel. The process will be similar for most routers.

    Fixing DNS Rebinding

    To resolve DNS rebinding issues and ensure smooth access to your local services, follow these steps:

    1. Configure DNS Rewrites in AdGuard
      In AdGuard Home, go to Filters → DNS Rewrites, and add your domain along with the Pi’s local IP address. This will ensure local access to your services without DNS rebinding errors.

    2. SSL Setup for Local Domains
      To securely use your local domains, I used Cloudflare to manage SSL certificates.you can follow this topic that explain well this step sHere’s a summary of the steps:

      • Buy a domain from a registrar (I used Namecheap).

      • Set up DNS in Cloudflare to point to the Raspberry Pi’s local IP address.


Adding SSL Certificates and Proxy Hosts in NPM

Step 1: Connect AdGuard to NPM

Before setting up SSL for AdGuard (or any other service), ensure it’s connected to NPM:

  1. Go to Portainer → Containers and find the nginx_proxy_manager-app-1 container (or your NPM container name).

  2. Scroll down to the Connected Networks section.

  3. Join the AdGuard network so NPM can communicate with it.

Step 2: Add an SSL Certificate

  1. Open Nginx Proxy Manager (NPM).

  2. Go to SSL Certificates and click Add SSL Certificate.

  3. Use Let's Encrypt with Cloudflare DNS to validate the certificate.

    • Make sure your domain & subdomain is already set up in Cloudflare and points to your local IP.

Step 3: Create a Proxy Host

  1. In NPM, navigate to Hosts → Proxy Hosts and click Add Proxy Host.

  2. Fill in the details:

    • Domain Name: Enter the domain or subdomain (e.g., adguard.localdomain.com).

    • Forward Hostname/IP: Enter the local IP of the service (e.g., your Raspberry Pi’s IP).

    • Forward Port: Enter the port where the service is running.

  3. Go to the SSL Tab and select the SSL certificate you created earlier.

  4. Enable the following options for better security and performance:

    • Force SSL (redirects all traffic to HTTPS).

    • HTTP/2 Support (makes things faster and smoother).

  5. Save your settings.

Step 4: Test Your Setup

Open your browser and visit the domain or subdomain you just set up. You should see the service running securely over HTTPS.

Step 5: Repeat for Other Services

For each additional service, follow the same process:

  • Make sure the service is connected to NPM’s network in Portainer.

  • Add a proxy host in NPM with the correct domain, IP, port, and SSL certificate.

That’s it! Your services are now secured and easily accessible with clean, HTTPS-enabled URLs. 🎉


Trying Out an App: Wallos

With everything set up, it’s time to have some fun and test an app! I decided to try Wallos, a handy tool for managing subscriptions. Here’s how I got it up and running:

Step 1: Add Wallos in Portainer

In Portainer, create a new stack and use the following configuration:

yamlCopier le codeservices:
  wallos:
    container_name: wallos
    image: bellamy/wallos:latest
    ports:
      - "8282:80"
    volumes:
      - './db:/var/www/html/db'
      - './logos:/var/www/html/images/uploads/logos'
    restart: unless-stopped

Step 2: Connect Wallos to NPM

Once the stack is deployed, connect Wallos to the Nginx Proxy Manager network:

  1. Go to Portainer → Containers and locate the wallos container.

  2. Scroll to the Connected Networks section and join the network used by Nginx Proxy Manager.

Step 3: Create a Proxy Host for Wallos

In NPM, set up a new proxy host:

  • Enter your domain name (e.g., wallos.localdomain.com).

  • Set the local IP and port (8282) for the Wallos container.

  • Select your SSL certificate, enable Force SSL, and save.

Step 4: Test Wallos

Now, open your browser and visit the domain you set up. You should see Wallos ready to manage your subscriptions securely and efficiently! 🎉

Wrapping Up

This journey has been an incredible learning experience. From fixing tricky DNS rebinding issues to configuring SSL for local domains, every step was a mix of challenges and triumphs. Each error pushed me to explore new concepts, and the solutions taught me skills I never thought I’d need.

But this is just the beginning! There’s so much more to discover in the world of homelabs, and I can’t wait to see where this adventure takes me next. 🚀

0
Subscribe to my newsletter

Read articles from Ayoub Touba directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayoub Touba
Ayoub Touba

With over a decade of hands-on experience, I specialize in building robust web applications and scalable software solutions. My expertise spans across cutting-edge frameworks and technologies, including Node.js, React, Angular, Vue.js, and Laravel. I also delve into hardware integration with ESP32 and Arduino, creating IoT solutions.