Proxmox + Home Assistant OS+ Frigate (worksheet)
THE TUTORIAL IS MEANT TO BE USED WITH THIS VIDEO!
Proxmox VE 9.2, Home Assistant OS in a VM, Frigate 0.17 in Docker on a Debian VM. September 2026.
What you end up with: Proxmox with two virtual machines on it. VM 100 is Home Assistant OS. VM 101 is a small Debian machine running Docker, with Frigate inside it and your camera recordings on their own virtual disk. At the end, Frigate's cameras and events show up inside Home Assistant.
Before You Start
A PC or mini PC with at least 4 cores and 16 GB of RAM. 8 GB works if you trim the VM sizes in Steps 5 and 7. Anything from about 2015 forward, or an N100/N150 mini PC, is a good fit. (Video uses: Ryzen 7 2700, 32 GB, 128 GB NVMe for Proxmox, 2 TB SATA SSD for recordings, 2.5 Gbit Ethernet.)
An SSD for Proxmox and the VMs. A second, bigger drive (SSD or spinning) for recordings is nice but optional.
A USB stick, 4 GB or larger. It gets erased.
A keyboard and monitor for the box, just for the install. After that, everything is a browser tab.
Wired Ethernet. Do not run this over WiFi.
A free GitHub account (for HACS in Step 6).
Commands run in one of three places: the Proxmox shell (web UI, click your node, then Shell), the VM console (web UI, click the VM, then Console), or an SSH session to the Frigate VM. Each step says which. Paste multi-line blocks in one go.
My Proxmox IP (static, outside the DHCP pool): ______________________________
My Home Assistant IP: ______________________________
My Frigate VM IP: ______________________________
(example: 192.168.0.20, .21, .22. Give all three a DHCP reservation in your router so they never move.)
Step 1 - Prepare the Proxmox Installer
1.1 - Download the Proxmox VE 9.2 ISO: proxmox.com/en/downloads (proxmox-ve_9.2-1.iso, about 1.7 GB)
1.2 - Download balenaEtcher: etcher.balena.io (Rufus works too; if Rufus asks, choose DD image mode)
1.3 - Flash the ISO to the USB stick.
1.4 - Boot from the stick: plug it into the box, power on, and press the boot menu key (usually F12, F11, F8, or Esc).
1.5 - While you are in the BIOS: turn ON virtualization (Intel VT-x or AMD SVM) AND the IOMMU (Intel VT-d or AMD-Vi). You will want both later.
Step 2 - Install Proxmox
2.1 - Choose Install Proxmox VE (Graphical), agree to the license.
2.2 - Target Harddisk: pick your SSD. Leave the filesystem at ext4 unless you know you want ZFS. Everything on that drive is erased.
2.3 - Country, timezone, keyboard layout.
2.4 - Root password and email. This is the login for the web UI.
Root password: ______________________________
2.5 - Management network: pick the wired interface. Static IP from the box above, outside your router's DHCP pool.
Hostname (FQDN, video uses pve.home.arpa): ______________________________
Gateway (your router): ______________________________
DNS server: ______________________________
2.6 - Install. Pull the USB stick when it reboots.
2.7 - Log in from another computer: https://YOUR-PROXMOX-IP:8006. Click through the certificate warning. Username root, the password from above, Realm: Linux PAM.
You can unplug the monitor and keyboard now.
Step 3 - Post-Install Cleanup
Proxmox shell
3.1 - Run the community post-install script:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/post-pve-install.sh)"
Answer Yes to: correct sources, disable the enterprise repositories, enable the no-subscription repository, disable the subscription nag, update Proxmox, and reboot. Answer No to anything about Ceph or the test repository.
3.2 - After it comes back, log in again. Node > Updates should show nothing pending.
Step 4 - (Optional) Add a Recordings Drive
Skip this if everything lives on the one SSD.
4.1 - Node > Disks: find your second drive and note its device name (sdb, nvme1n1, and so on). If it has old partitions, select it and click Wipe Disk.
4.2 - Node > Disks > Directory > Create: Directory. Pick the disk, filesystem ext4, Name: recordings, Add Storage checked.
Recordings storage name (video uses recordings): ______________________________
Step 5 - Create the Home Assistant OS VM
Proxmox shell
5.1 - Run the HAOS VM script:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/haos-vm.sh)"
5.2 - Choose Advanced settings and set:
- Version: stable
- VM ID: 100
- Hostname: haos
- CPU model: Host. Do NOT leave it on KVM64. Current Home Assistant OS needs the x86-64-v2 feature set and will boot to the ha > prompt with no web UI on KVM64. Pick x86-64-v2-AES instead of Host only if you plan to live-migrate the VM around a cluster later.
- CPU cores: 2 (4 if you plan to run voice assistants or Music Assistant)
- RAM: 4096
- Disk size: 32
- Bridge: vmbr0
- Start VM when completed: yes
5.3 - Wait. Click VM 100, then Console. First boot takes a few minutes and ends at a ha > prompt. Then Home Assistant does its own first-time setup, which can take another 5 to 20 minutes.
5.4 - Find the IP in your router's client list (hostname homeassistant), or in the console:
network info
Set a DHCP reservation for it and write it in the box at the top.
5.5 - Onboard: open http://YOUR-HA-IP:8123. Create your owner account, name the home, set location, skip or accept the analytics choices.
HA username: ______________________________
HA password: ______________________________
5.6 - Confirm Settings > Apps exists before moving on. (Home Assistant renamed add-ons to Apps in early 2026; older guides still say Add-ons.) If it is missing, the Supervisor is still starting; wait a few minutes and reload the page. Settings > About should say Installation type: Home Assistant OS and list a Supervisor version. If it still will not appear, Settings > System > Repairs usually says why (most often no internet or DNS from the VM), and a reboot of VM 100 clears it more often than not.
Step 6 - Get Home Assistant Ready for Frigate
Frigate talks to Home Assistant over MQTT, so the broker goes in now. All of this is in the Home Assistant web UI.
6.1 - MQTT user: Settings > People > Users > Add User. Display name: mqtt, username: mqtt, pick a password. Uncheck Administrator. Save.
MQTT password: ______________________________
6.2 - Mosquitto broker: Settings > Apps > Install app (top right) > search Mosquitto broker > Install. Turn on Start on boot and Watchdog, then Start.
6.3 - MQTT integration: Settings > Devices & services. Home Assistant should have discovered MQTT. Click Configure and Submit. If it did not: Add Integration > MQTT, broker core-mosquitto, port 1883, username mqtt, password from above.
6.4 - HACS (the Home Assistant Community Store) is where the Frigate integration comes from. It is third-party, so it is not in the app store until you add its repository:
- Settings > Apps > Install app > three-dot menu (top right) > Repositories. Paste https://github.com/hacs/addons, click Add, close, reload the page.
- Install Get HACS (Home Assistant Community Store), start it, and watch its Log tab. It tells you to restart Home Assistant: Settings > System > Restart.
- After the restart: Settings > Devices & services > Add Integration > HACS. Follow the GitHub device login it gives you.
- HACS now shows up in the left sidebar. If it does not, the integration step was skipped: go back to Add Integration.
Step 7 - Create the Frigate (Docker) VM
Proxmox shell
7.1 - Run the Docker VM script:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/docker-vm.sh)"
7.2 - Choose Advanced settings and set:
- OS: Debian 13 (Trixie)
- VM ID: 101
- Hostname: frigate
- CPU type: Host
- CPU cores: 4
- RAM: 4096 (8192 if you will run more than 4 cameras)
- Disk size: 32 (the default is 10, and Frigate's image alone is almost 2 GB)
- Bridge: vmbr0
- Cloud-Init: No (the console auto-logs in as root, which is all we need)
- Start VM when completed: yes
Give it a minute or two after boot; Docker installs itself in the background on first boot.
7.3 - First login, in the VM 101 console (you land at a root prompt with no password). Set one, make a normal user, make sure SSH is there, and set the timezone. The cloud image ships without a timezone and Frigate will not start without one. Use yours; timedatectl list-timezones shows them all.
passwd
apt update && apt install -y sudo openssh-server
adduser netserv
usermod -aG sudo,docker netserv
timedatectl set-timezone America/New_York
ip -4 addr show | grep inet
netserv password: ______________________________
Write the IP in the box at the top and reserve it in your router.
7.4 - Switch to SSH from your computer (Windows: Windows+R, type cmd, Enter). Use your username and IP. Everything from here on runs in this SSH session.
ssh netserv@192.168.0.22
7.5 - Confirm Docker is up:
docker --version && docker compose version
If it says docker is not found, first boot is still installing it. Wait a minute and try again.
Step 8 - Recordings Disk for the VM
8.1 - Shut the VM down: VM 101 > Shutdown.
8.2 - VM 101 > Hardware > Add > Hard Disk. Storage: recordings (from Step 4, or local-lvm if you skipped it). Disk size: as big as you can spare (video uses 500 GB). Leave the rest at defaults. Start the VM and SSH back in.
8.3 - Find the new disk (the one with no partitions, usually sdb):
lsblk
8.4 - Format and mount it. Double-check the device name; this erases the disk. The fstab line has NO space after the comma.
sudo mkfs.ext4 -L frigate /dev/sdb
sudo mkdir -p /media/frigate
echo 'LABEL=frigate /media/frigate ext4 defaults,nofail 0 2' | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount -a
df -h /media/frigate
Step 9 - Install Frigate
9.1 - Make the folders:
mkdir -p ~/frigate/config && cd ~/frigate
9.2 - Create the compose file. Paste this whole block at the prompt in one go, exactly as it is. It writes the file for you, so the indentation comes through intact (YAML is picky about it, and pasting into an editor line by line tends to lose the spaces).
cat > ~/frigate/docker-compose.yml <<'EOF'
services:
frigate:
container_name: frigate
privileged: true
restart: unless-stopped
stop_grace_period: 30s
image: ghcr.io/blakeblackshear/frigate:stable
shm_size: "512mb"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./config:/config
- /media/frigate:/media/frigate
- type: tmpfs
target: /tmp/cache
tmpfs:
size: 1000000000
ports:
- "8971:8971"
- "5000:5000"
- "8554:8554"
- "8555:8555/tcp"
- "8555:8555/udp"
EOF
9.3 - Check it:
docker compose config --quiet && echo OK
9.4 - Create the config file the same way. Paste it as-is first; you fill in your values in the next step.
cat > ~/frigate/config/config.yml <<'EOF' mqtt: enabled: true host: YOUR-HA-IP user: mqtt password: YOUR-MQTT-PASSWORDdetectors: cpu1: type: cpu num_threads: 3
record: enabled: true retain: days: 7 mode: motion alerts: retain: days: 30 detections: retain: days: 30
snapshots: enabled: true retain: default: 30
objects: track: - person - car - dog - cat
cameras: front_door: ffmpeg: output_args: record: preset-record-generic-audio-aac inputs: - path: rtsp://USER:PASS@CAMERA-IP:554/h264Preview_01_main roles: - record - path: rtsp://USER:PASS@CAMERA-IP:554/h264Preview_01_sub roles: - detect detect: width: 640 height: 360 fps: 5 EOF
9.5 - Fill in your values. Only change the text after the colons.
nano config/config.yml
Save with Control-X, then Y, then Enter.
Notes on that file:
- Detection runs on the CPU in this worksheet, which is fine for a camera or two on substreams. Coral, iGPU, and dedicated GPU detection are a separate video; the change when you get there is just the detectors block and a couple of compose lines.
- The output_args line converts the camera's audio to AAC so recordings have sound. Reolink (and most other cameras) send G.711 audio, which MP4 recordings cannot hold; without this line Frigate's Stream Validation shows a red AAC warning and your clips are silent. Delete the two lines if you do not want audio.
- The camera URLs shown are Reolink. Amcrest/Dahua and Hikvision patterns are on the RTSP Camera Monitor worksheet. Frigate's docs push Reolink users toward its HTTP-FLV streams through go2rtc; I have had better luck with plain RTSP, so that is what is here. Use a view-only camera account with an alphanumeric password.
- The detect width and height must match your substream resolution. Reolink substreams are 640x360; check yours in the camera's web UI under Stream.
- Copy the front_door block for each additional camera and change the name and IP.
Camera 1 name, IP, substream size: ______________________________
Camera 2 name, IP, substream size: ______________________________
Camera 3 name, IP, substream size: ______________________________
Camera 4 name, IP, substream size: ______________________________
9.6 - Start it and watch the log:
docker compose up -d
docker logs -f frigate
The first start pulls a big image and takes a few minutes. Two lines matter: one that says it created an admin user and shows a PASSWORD, and one that says the detector started. Press Control-C to stop following the log; Frigate keeps running.
9.7 - Grab the admin password. It is only printed once, near the top, and it scrolls by fast:
docker logs frigate 2>&1 | grep -i -B3 -A3 password
Frigate admin password: ______________________________
9.8 - Log in: https://YOUR-FRIGATE-IP:8971. Click through the certificate warning, log in as admin. You should see your cameras. Settings > Users lets you change the password to something you can remember.
System metrics shows detector inference speed. On CPU, expect somewhere between 60 and 150 ms and a noticeable CPU load; that is normal, and it is the reason the next video is about hardware detectors.
To change the config later, either edit config/config.yml over SSH and run docker compose restart, or use the editor in Frigate's own UI under Configuration, which saves and restarts for you.
Step 10 - Connect Frigate to Home Assistant
In the Home Assistant web UI
10.1 - Download the integration: HACS (left sidebar) > click the search box at the top > type Frigate. Pick the entry by blakeblackshear, then Download (bottom right) and confirm. Restart Home Assistant (Settings > System > Restart).
If the search comes up empty, HACS is still pulling its list; give it five minutes and reload. Still nothing: three-dot menu (top right of the HACS page) > Custom repositories, paste https://github.com/blakeblackshear/frigate-hass-integration, type Integration, Add, then search again.
10.2 - Add the integration: Settings > Devices & services > Add Integration > Frigate. URL: http://YOUR-FRIGATE-IP:5000 (the unauthenticated port we mapped in the compose file; it only answers on your LAN, so keep the Frigate VM off any network you don't trust). Submit.
You get one device per camera, with live view, motion and object sensors, a switch for detection and recording, and Frigate's clips in the Media browser. Add a camera card to a dashboard and you are done.
10.3 - (Optional) Prove the chain: Settings > Devices & services > MQTT > Configure > Listen to a topic frigate/events, then walk in front of a camera. Watching events land is a good way to know the whole thing works.
Daily Use
- Proxmox: https://PROXMOX-IP:8006. VM 100 and 101 start automatically at boot.
- Home Assistant: http://HA-IP:8123
- Frigate: https://FRIGATE-IP:8971
- Watch a camera on anything that plays RTSP (VLC, the Pi camera monitor): rtsp://FRIGATE-IP:8554/front_door
If It Doesn't Work
Web UI at :8006 will not load after install: the IP or gateway from Step 2 is wrong. Plug the monitor back in, log in as root at the text console, edit /etc/network/interfaces, then run ifreload -a.
The helper script says your Proxmox version is not supported: run Node > Updates > Upgrade first, or the script is newer than the host. Reboot and retry.
HAOS console reaches ha > but :8123 never answers, even after 20 minutes: the CPU model is KVM64. Shut the VM down, VM 100 > Hardware > Processors > Edit > Type: host, start it again.
HAOS VM boots to a blank screen or loops: the VM must be UEFI (OVMF). The script does that for you; if you made the VM by hand, that is the usual miss.
Docker VM console shows no prompt: press Enter. If it asks for a login, the image booted before first-boot setup finished; wait a minute and press Enter again.
docker compose up fails with no space left on device: the VM disk was left at the script's 10 GB default. Check with df -h /. Grow it without reinstalling: VM 101 > Hardware > Hard Disk (scsi0) > Disk Action > Resize, add 22 GB. Then in the VM (lsblk shows the disk and partition names, usually sda and sda1):
sudo apt install -y cloud-guest-utils
sudo growpart /dev/sda 1
sudo resize2fs /dev/sda1
docker system prune -af
docker compose up -d
Frigate will not start and the error mentions /etc/localtime and not a directory: the timezone step in 7.3 was skipped and Docker created an empty folder in its place. Run sudo rm -rf /etc/localtime, then sudo timedatectl set-timezone America/New_York, then docker compose up -d.
mount -a complains about fstab: there is a space after the comma in the line from 8.4. It must read defaults,nofail with no space.
Frigate runs but the VM is pegged at 100 percent CPU: lower detect fps to 3, make sure detect is on the substream and not the main stream, and give the VM more cores. Or wait for the hardware detector video.
Lost the admin password: add auth: on its own line at the top level of config.yml, with reset_admin_password: true indented under it, then docker compose restart and run the grep from 9.7. Frigate clears the flag itself after printing the new password.
Frigate will not start at all: docker logs frigate. Nine times out of ten it is YAML indentation in config.yml.
Camera shows a broken image: test the RTSP URL in VLC on your computer first (Media > Open Network Stream). If VLC fails, the URL or credentials are wrong.
Stream Validation shows a red AAC audio warning: the output_args line from 9.4 is missing. Recordings will be silent until it is there.
Detection works but recordings are empty: df -h /media/frigate. If the mount is gone, the fstab line from 8.4 is wrong; also make sure the disk was added to the VM before the mount.
Home Assistant Frigate integration cannot connect: from any computer, open http://FRIGATE-IP:5000/api/version. If that fails, the port mapping in the compose file is missing or a firewall between VLANs is blocking it.
MQTT sensors never update: Frigate's log will say it could not connect to the broker. Check the host and password in config.yml, and that the mqtt user exists in Home Assistant.
Maintenance
Proxmox, every month or so: Node > Updates > Refresh, then Upgrade. Reboot if it installed a kernel.
Home Assistant: Settings > System > Updates. Take a backup first (Settings > System > Backups). Also take a Proxmox snapshot of VM 100 before major updates: VM 100 > Snapshots > Take Snapshot.
Frigate: read the release notes first (major versions sometimes change config keys), then:
cd ~/frigate && docker compose pull && docker compose up -d
- Debian VM packages:
sudo apt update && sudo apt full-upgrade -y
- Backups: Datacenter > Backup > Add. Pick both VMs, weekly, to your recordings storage or a NAS. Exclude the recordings disk: VM 101 > Hardware > the big disk > Edit > uncheck Backup.
Links
Proxmox VE downloads: proxmox.com/en/downloads
Proxmox community helper scripts: community-scripts.org
Home Assistant OS on Proxmox script: community-scripts.org/scripts/haos-vm
Docker VM script: community-scripts.org/scripts/docker-vm
Frigate docs: docs.frigate.video
Frigate Home Assistant integration: docs.frigate.video/integrations/home-assistant
HACS: hacs.xyz
Related worksheets: RTSP Camera Monitor (camera URL patterns), Tailscale Subnet Router (reach all of this from the road)