Forked from 1ofeightbillion-hub/Home Server Guide: Proxmox + HAOS + Frigate + Coral TPU (Verified Working Build)
Created
November 8, 2025 12:02
-
-
Save kenrmayfield/bec2900918e452ff2e6947a414b20f73 to your computer and use it in GitHub Desktop.
Home Server Guide: Proxmox + HAOS + Frigate + Coral TPU (Verified Working Build)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 🏡 Home Server Guide: Proxmox + HAOS + Frigate + Coral TPU | |
| (Verified Working Build — Minimal First → Add Complexity Later) | |
| This guide walks through building a reliable, low-maintenance **home-automation** and **NVR setup** using: | |
| * **Proxmox VE** (host virtualization platform) | |
| * **Home Assistant OS (HAOS)** in a VM | |
| * **Frigate NVR** in a Debian 12 LXC (Docker-based) | |
| * *Optional:* **Coral TPU** (object-detection acceleration) | |
| * *Optional:* **GPU decoding** (Intel iGPU) | |
| * *Optional:* **rclone** Google Drive continuous backup and storage cap | |
| The first half builds a **minimal working setup** (guaranteed to work). The second half adds **advanced features** once the base is running cleanly. | |
| --- | |
| ## PART 1 – MINIMAL WORKING SETUP | |
| ### 1️⃣ Install Proxmox VE (PVE) | |
| **Purpose:** Base virtualization platform that hosts HAOS (VM) and Frigate (LXC). | |
| #### Steps | |
| 1. **Download & Install** | |
| * Get the ISO from the official Proxmox website. | |
| * Write to a USB drive (using Rufus or Balena Etcher), boot, and install with the default settings. | |
| 2. **Fix Enterprise Repository** | |
| * *PVE is free, but we disable the paid enterprise repo to avoid update errors.* | |
| ```bash | |
| # Disable the enterprise repository | |
| sed -i 's|^deb .*pve-enterprise|# &|' /etc/apt/sources.list.d/pve-enterprise.list | |
| # Add the no-subscription repository | |
| echo "deb [http://download.proxmox.com/debian/pve](http://download.proxmox.com/debian/pve) bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list | |
| # Update and upgrade | |
| apt update && apt full-upgrade -y | |
| ``` | |
| 3. **Install Utilities** | |
| ```bash | |
| apt install -y htop iotop curl jq usbutils unattended-upgrades | |
| dpkg-reconfigure -plow unattended-upgrades | |
| ``` | |
| 4. **Verify Hardware** | |
| ```bash | |
| uname -a | |
| lscpu | |
| lsusb | |
| lspci | grep -E "VGA|3D|Display" | |
| ``` | |
| --- | |
| ### 2️⃣ Install Home Assistant OS (HAOS) VM | |
| **Purpose:** Runs automations and smart-home integrations. | |
| #### Steps | |
| 1. **Download & Decompress the QCOW2 Image** | |
| * Run these commands from your Proxmox shell. | |
| ```bash | |
| wget [https://github.com/home-assistant/operating-system/releases/latest/download/haos_ova.qcow2.xz](https://github.com/home-assistant/operating-system/releases/latest/download/haos_ova.qcow2.xz) | |
| xz -d haos_ova.qcow2.xz | |
| mv haos_ova.qcow2 haos.qcow2 | |
| ``` | |
| 2. **Create VM and Import Disk** | |
| * `100` is the VM ID. Adjust resources as needed. | |
| ```bash | |
| qm create 100 --name haos --memory 4096 --cores 2 --net0 virtio,bridge=vmbr0 | |
| qm importdisk 100 haos.qcow2 local-lvm | |
| qm set 100 --scsihw virtio-scsi-single --scsi0 local-lvm:vm-100-disk-0 | |
| qm set 100 --boot order=scsi0 | |
| qm set 100 --bios ovmf | |
| qm set 100 --efidisk0 local-lvm:vm-100-efi,size=4M,pre-enrolled-keys=1 | |
| qm start 100 | |
| ``` | |
| 3. **Access HAOS** | |
| * Access via browser: `http://homeassistant.local:8123` or `http://<VM-IP>:8123` | |
| --- | |
| ### 3️⃣ Install Frigate NVR (Minimal Config) | |
| **Purpose:** Provide NVR with both continuous and event-based recording. Frigate runs inside a Debian 12 **LXC** container using **Docker**. | |
| #### Steps | |
| 1. **Create LXC Container** | |
| * `101` is the LXC ID. Adjust resources as needed. | |
| ```bash | |
| pct create 101 local:vztmpl/debian-12-standard_12.0-1_amd64.tar.zst \ | |
| --hostname frigate --memory 4096 --cores 4 \ | |
| --net0 name=eth0,bridge=vmbr0,ip=dhcp \ | |
| --rootfs local-lvm:16 \ | |
| --features nesting=1,fuse=1 | |
| pct start 101 | |
| pct exec 101 -- bash | |
| ``` | |
| 2. **Install Docker (Inside the LXC)** | |
| ```bash | |
| apt update | |
| apt install -y ca-certificates curl gnupg lsb-release | |
| install -m 0755 -d /etc/apt/keyrings | |
| curl -fsSL [https://download.docker.com/linux/debian/gpg](https://download.docker.com/linux/debian/gpg) | gpg --dearmor -o /etc/apt/keyrings/docker.gpg | |
| chmod a+r /etc/apt/keyrings/docker.gpg | |
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] [https://download.docker.com/linux/debian](https://download.docker.com/linux/debian) $(. /etc/os-release && echo $VERSION_CODENAME) stable" > /etc/apt/sources.list.d/docker.list | |
| apt update | |
| apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin | |
| systemctl enable --now docker | |
| ``` | |
| 3. **Create Frigate Folders and Files** | |
| ```bash | |
| mkdir -p /opt/frigate/{config,storage} | |
| cd /opt/frigate | |
| ``` | |
| 4. **Create `docker-compose.yml`** | |
| ```yaml | |
| version: "3.9" | |
| services: | |
| frigate: | |
| container_name: frigate | |
| image: ghcr.io/blakeblackshear/frigate:stable | |
| restart: unless-stopped | |
| privileged: true | |
| shm_size: "256m" | |
| environment: | |
| TZ: "America/Chicago" # <-- Set your Timezone | |
| volumes: | |
| - /opt/frigate/config:/config | |
| - /opt/frigate/storage:/media/frigate | |
| ports: | |
| - "5000:5000" | |
| - "1984:1984" | |
| - "8554:8554" | |
| - "8555:8555/tcp" | |
| - "8555:8555/udp" | |
| ``` | |
| 5. **Create Minimal `config.yml`** | |
| * ***Important:*** *Replace `<USER>`, `<PASS>`, and `<CAM-IP>` with your camera's details.* | |
| ```yaml | |
| mqtt: | |
| enabled: false | |
| detectors: | |
| cpu1: | |
| type: cpu | |
| record: | |
| enabled: true | |
| retain: | |
| days: 1 | |
| events: | |
| retain: | |
| default: 1 | |
| snapshots: | |
| enabled: true | |
| timestamp: true | |
| bounding_box: true | |
| go2rtc: | |
| streams: {} | |
| cameras: | |
| example_camera: # <-- Name your camera | |
| ffmpeg: | |
| inputs: | |
| - path: rtsp://<USER>:<PASS>@<CAM-IP>:554/stream1 # <-- High-res stream for record | |
| roles: [record] | |
| - path: rtsp://<USER>:<PASS>@<CAM-IP>:554/stream2 # <-- Low-res stream for detect | |
| roles: [detect] | |
| detect: | |
| width: 640 | |
| height: 360 | |
| fps: 5 | |
| record: | |
| enabled: true | |
| retain: | |
| days: 1 | |
| snapshots: | |
| enabled: true | |
| ``` | |
| 6. **Start Frigate** | |
| ```bash | |
| cd /opt/frigate | |
| docker compose up -d | |
| docker ps | |
| ``` | |
| 7. **Access Frigate UI** | |
| * Access via browser: `http://<LXC-IP>:5000` | |
| --- | |
| ## PART 2 – ADD COMPLEXITY LATER | |
| ### 4️⃣ Add Coral TPU (Optional) | |
| #### Proxmox Configuration | |
| 1. Verify the Coral is connected to the PVE host. | |
| ```bash | |
| lsusb | grep -i "coral" | |
| ``` | |
| 2. Edit the LXC configuration file on the **Proxmox host** (`/etc/pve/lxc/101.conf`). | |
| ```conf | |
| # Add this line to the bottom | |
| lxc.mount.entry: /dev/bus/usb /dev/bus/usb none bind,optional,create=dir | |
| ``` | |
| #### Frigate Configuration | |
| 1. Add the `devices` section to your `docker-compose.yml` (inside the LXC). | |
| ```yaml | |
| # ... inside 'frigate' service block | |
| # ... (shm_size, environment, volumes, etc.) | |
| devices: | |
| - /dev/bus/usb:/dev/bus/usb | |
| ports: | |
| # ... | |
| ``` | |
| 2. Update the `detectors` block in your `config.yml` (inside the LXC). | |
| ```yaml | |
| detectors: | |
| coral: | |
| type: edgetpu | |
| device: usb | |
| cpu1: | |
| type: cpu | |
| ``` | |
| 3. Restart Frigate. | |
| ```bash | |
| cd /opt/frigate | |
| docker compose restart frigate | |
| ``` | |
| --- | |
| ### 5️⃣ Add iGPU Decoding (Optional) | |
| This step reduces CPU usage by offloading video decoding to an Intel iGPU. | |
| #### Proxmox Configuration | |
| 1. Edit the LXC configuration file on the **Proxmox host** (`/etc/pve/lxc/101.conf`). | |
| ```conf | |
| # Add these two lines to the bottom | |
| lxc.cgroup2.devices.allow: c 226:* rwm | |
| lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir | |
| ``` | |
| #### Frigate Configuration | |
| 1. Add the `hwaccel_args` to the `ffmpeg` block for each camera in your `config.yml` (inside the LXC). | |
| ```yaml | |
| cameras: | |
| example_camera: | |
| ffmpeg: | |
| hwaccel_args: preset-vaapi # <-- Add this line | |
| inputs: | |
| # ... | |
| ``` | |
| 2. Restart Frigate. | |
| ```bash | |
| cd /opt/frigate | |
| docker compose restart frigate | |
| ``` | |
| --- | |
| ### 6️⃣ Add Google Drive Backup (rclone) | |
| This is set up inside the Frigate LXC (`101`). | |
| 1. **Install rclone and inotify-tools** | |
| ```bash | |
| apt install -y rclone inotify-tools | |
| rclone config # <-- Follow prompts to set up your Google Drive remote (e.g., named 'gdrive') | |
| ``` | |
| 2. **Real-time Uploader Script** | |
| * Create the script `/usr/local/bin/frigate_upload_watch.sh`. | |
| ```bash | |
| #!/usr/bin/env bash | |
| SRC="/opt/frigate/storage" | |
| DEST="gdrive:Frigate_Backups" # <-- Update 'gdrive' if your remote name is different | |
| LOG="/var/log/frigate_rclone.log" | |
| inotifywait -m -r -e close_write,moved_to,create "$SRC" | \ | |
| while read -r dir action file; do | |
| rclone copyto "$dir/$file" "$DEST/${dir#${SRC}/}/$file" \ | |
| --log-file="$LOG" --log-level INFO --update | |
| done | |
| ``` | |
| 3. **Create Systemd Service** | |
| * Create the file `/etc/systemd/system/frigate-upload-watch.service`. | |
| ```systemd | |
| [Unit] | |
| Description=Frigate -> Google Drive uploader | |
| After=network-online.target | |
| [Service] | |
| Type=simple | |
| ExecStart=/usr/local/bin/frigate_upload_watch.sh | |
| Restart=always | |
| RestartSec=3 | |
| User=root | |
| [Install] | |
| WantedBy=multi-user.target | |
| ``` | |
| 4. **Start and Enable Service** | |
| ```bash | |
| systemctl daemon-reload | |
| systemctl enable --now frigate-upload-watch.service | |
| ``` | |
| --- | |
| ### 7️⃣ Add Drive Storage Cap (Optional) | |
| This is a script to automatically delete the oldest files from the Google Drive remote when the storage limit is reached. | |
| 1. **Config File** | |
| * Create `/etc/gdrive_cap.conf`. | |
| ```conf | |
| REMOTE="gdrive:Frigate_Backups" # <-- Match your rclone remote | |
| CAP_BYTES="500G" # <-- Set your storage cap | |
| ``` | |
| 2. **Enforcer Script** | |
| * Create `/usr/local/bin/gdrive_cap_enforcer.sh`. | |
| ```bash | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| source /etc/gdrive_cap.conf | |
| CAP=$(numfmt --from=iec $CAP_BYTES) | |
| current=$(rclone lsf "$REMOTE" --files-only --format s --recursive | awk '{s+=$1} END{print s+0}') | |
| if [ "$current" -le "$CAP" ]; then exit 0; fi | |
| rclone lsf "$REMOTE" --files-only --format pst --separator '|' --recursive | sort -t'|' -k3,3 | \ | |
| while IFS='|' read -r path size mtime; do | |
| [ "$current" -le "$CAP" ] && break | |
| rclone deletefile "$REMOTE/$path" | |
| current=$(( current - size )) | |
| done | |
| ``` | |
| 3. **Create Systemd Timer** | |
| * Create `/etc/systemd/system/gdrive-cap-enforcer.timer`. | |
| ```systemd | |
| [Timer] | |
| OnBootSec=2min | |
| OnUnitActiveSec=10min # <-- How often to run the check | |
| AccuracySec=1min | |
| Unit=gdrive-cap-enforcer.service | |
| [Install] | |
| WantedBy=timers.target | |
| ``` | |
| 4. **Create Systemd Service for the Enforcer (for the timer to call)** | |
| * Create `/etc/systemd/system/gdrive-cap-enforcer.service`. | |
| ```systemd | |
| [Unit] | |
| Description=Frigate Google Drive Capacity Enforcer | |
| Requires=gdrive-cap-enforcer.timer | |
| [Service] | |
| Type=oneshot | |
| ExecStart=/usr/local/bin/gdrive_cap_enforcer.sh | |
| ``` | |
| 5. **Start and Enable Timer** | |
| ```bash | |
| systemctl daemon-reload | |
| systemctl enable --now gdrive-cap-enforcer.timer | |
| ``` | |
| --- | |
| ## 🚀 Workflow Summary | |
| | Step | Component | Purpose | | |
| | :--- | :--- | :--- | | |
| | **1** | Proxmox | Base OS / Virtualization Host | | |
| | **2** | HAOS (VM) | Runs Home Automation / Integrations | | |
| | **3** | Frigate (LXC + Docker) | NVR for Recording and Detection (CPU-only) | | |
| | **4** | **Optional** Coral TPU | Accelerate Object Detection | | |
| | **5** | **Optional** iGPU Decoding | Lower CPU usage for video decoding | | |
| | **6** | **Optional** rclone | Real-time backup to Google Drive | | |
| | **7** | **Optional** Drive Cap | Auto-delete oldest cloud files to enforce a limit | | |
| **✅ End Result:** Frigate continuously records and shows events; HAOS runs separately; the system is **modular, stable, expandable, and easy to maintain**. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment