The Shift to Software-First SBC Development

When most makers think of beginner projects with Raspberry Pi, they immediately imagine blinking LEDs, breadboards, and GPIO wiring. However, the most powerful and scalable entry point into the single-board computer (SBC) ecosystem is entirely software-based. By treating your Raspberry Pi 4 or 5 as a headless Linux micro-server, you unlock enterprise-grade networking, smart home automation, and containerized deployments without spending a single dime on extra sensors or hardware modules.

This software walkthrough bypasses the hardware clutter. We will configure a headless Raspberry Pi OS Bookworm environment, install Docker Engine, and deploy two foundational projects: a network-wide ad blocker (Pi-hole) and a smart home hub (Home Assistant). Let's dive into the terminal and build a robust homelab node.

Phase 1: Headless Bookworm Setup (The NetworkManager Shift)

A critical failure point for beginners reading outdated tutorials is attempting to configure Wi-Fi via legacy methods. Older guides suggest dropping a wpa_supplicant.conf file into the boot partition to configure wireless networks. This no longer works. Raspberry Pi OS Bookworm officially replaced dhcpcd and wpa_supplicant with NetworkManager.

Using the Raspberry Pi Imager Correctly

To achieve a true headless setup (no monitor or keyboard required), you must use the official Raspberry Pi Imager's hidden advanced menu to inject your network configurations before the first boot.

  1. Open Raspberry Pi Imager and select Raspberry Pi OS Lite (64-bit). The "Lite" version lacks the desktop environment, saving roughly 400MB of RAM and reducing boot times by over 30%.
  2. Press Ctrl+Shift+X (or click the gear icon) to open Advanced Options.
  3. Set your hostname (e.g., pi-server.local).
  4. Enable SSH: Select Use password authentication and create a strong username/password combination. Avoid the default 'pi' user, which is deprecated for security reasons.
  5. Configure Wi-Fi: Enter your SSID, password, and crucially, the correct Wi-Fi Country Code. If omitted, the 5GHz radio will remain disabled by international regulatory safeguards.
Pro-Tip: If you are using a Raspberry Pi 5 with an active cooler, ensure your power supply delivers 27W via USB-C PD. Undervoltage warnings will throttle the CPU and cause Docker container builds to fail silently or corrupt your filesystem.

Phase 2: Installing Docker Engine on ARM64

Running software natively via apt or pip often leads to dependency hell, especially when mixing Python-based Home Assistant scripts with core system libraries. Docker isolates your beginner projects with Raspberry Pi into reproducible, secure containers.

SSH into your Pi using your local machine's terminal:

ssh your_username@pi-server.local

Next, install Docker using the official convenience script. This is the recommended method for ARM64 Debian-based systems, bypassing the outdated libffi-dev compilation errors common in older guides:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

Note: You must log out and log back in for the usermod group changes to take effect, allowing you to run Docker commands without sudo.

Bare Metal vs. Containerized Deployments

FeatureBare Metal (apt/pip)Docker Container
Dependency ConflictsHigh (System Python breakage)None (Isolated environments)
OS UpgradesRisky (Can break services)Safe (Containers persist)
Resource OverheadMinimal~50-100MB RAM per stack
PortabilityTied to Pi hardwareMove to any x86/ARM server

Phase 3: Deploying Pi-hole via Docker Compose

Pi-hole acts as a DNS sinkhole, blocking telemetry, trackers, and ads across your entire network. While you can install it directly on the OS, the official Pi-hole Docker documentation highly recommends containerization to prevent conflicts with local DNS resolvers and simplify updates.

Creating the Compose File

Create a dedicated directory for your project to keep your configurations organized:

mkdir -p ~/docker/pihole && cd ~/docker/pihole
nano docker-compose.yml

Paste the following ARM64-optimized configuration:

version: "3"
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      TZ: 'America/New_York'
      FTLCONF_LOCAL_IPV4: '192.168.1.50' # Replace with your Pi's static IP
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    restart: unless-stopped

Executing and Verifying

Pull the images and start the stack in detached mode:

docker compose up -d

Retrieve your auto-generated admin password by checking the container logs:

docker logs pihole 2>&1 | grep password

Navigate to http://pi-server.local/admin in your browser. To apply Pi-hole network-wide, log into your home router's admin panel and change the primary DNS server to your Raspberry Pi's IP address.

Phase 4: Adding Home Assistant Container

With Pi-hole handling your network DNS, let's tackle smart home automation. The Home Assistant installation guide offers multiple paths, but Home Assistant Container is ideal for SBCs running multiple services simultaneously.

mkdir -p ~/docker/homeassistant && cd ~/docker/homeassistant
nano docker-compose.yml
version: '3'
services:
  homeassistant:
    container_name: homeassistant
    image: "ghcr.io/home-assistant/home-assistant:stable"
    volumes:
      - ./config:/config
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    privileged: true
    network_mode: host

Using network_mode: host is critical here. It allows Home Assistant to discover mDNS and SSDP devices (like Chromecasts, Sonos speakers, and smart bulbs) on your local subnet, which is otherwise blocked by Docker's default bridge network isolation. If you plan to use a Zigbee USB dongle (like the Sonoff Zigbee 3.0 Plus), you will need to add a devices mapping to pass the /dev/ttyUSB0 path into the container.

Troubleshooting Common Software Bottlenecks

Even with containerization, you will encounter software roadblocks. Here is how to resolve the most frequent issues specific to the Raspberry Pi architecture:

  • Port 53 Conflict: If Pi-hole fails to bind to port 53, your host OS might be running systemd-resolved (common if you use Ubuntu Server instead of Pi OS). Fix this by editing /etc/systemd/resolved.conf, setting DNSStubListener=no, and restarting the service via systemctl restart systemd-resolved.
  • Thermal Throttling: Use the vcgencmd measure_temp command in the terminal. If your Pi 4 exceeds 80°C or your Pi 5 exceeds 85°C during Docker image pulls, the CPU will aggressively throttle. Invest in the official Active Cooler or an aluminum passive heatsink case to maintain peak ARM64 performance.
  • MicroSD Corruption: Docker writes extensive logs and database updates. Flashing a cheap, standard microSD card will result in block corruption and kernel panics within weeks. Upgrade to an Endurance-line microSD (e.g., SanDisk High Endurance or Samsung PRO Endurance) or, ideally, boot from a USB 3.0 NVMe enclosure using the rpi-eeprom-update tool to update your bootloader configuration.
  • Cgroup v2 Warnings: Bookworm utilizes cgroups v2 by default. If you see warnings about deprecated cgroup v1 memory limits in your Docker logs, ensure your containers are updated to the latest images, as older 2021-era images may fail to allocate memory correctly on modern Pi OS kernels.

Expanding Your SBC Stack

Mastering these beginner projects with Raspberry Pi transforms your SBC from a hobbyist toy into a reliable, always-on homelab node. Once you are comfortable with Docker Compose and YAML configurations, explore adding Portainer for GUI-based container management, or Nginx Proxy Manager to route traffic and generate local SSL certificates for your services. The software ecosystem is vast, and your terminal is the gateway to mastering it.

For further reading on optimizing ARM-based containers and managing persistent storage, refer to the Docker Engine installation docs and the official Raspberry Pi hardware forums.