Home Assistant can run on a VPS, but the architecture is different from a hub inside the house. A remote VPS is strong for cloud-facing integrations, dashboards, and automations that need a public data-center connection. It cannot directly discover LAN devices, reach USB Zigbee/Z-Wave radios in your home, or keep local automations working when the home internet path is down.
This guide installs Home Assistant Container on Ubuntu 24.04 LTS x86-64 with Docker Engine 23 or newer. Home Assistant OS is the upstream recommendation for most people and includes apps and Supervisor management. Home Assistant Container is the supported fit for a normal Linux VPS, but it does not include Home Assistant apps; you maintain Docker, networking, backups, and updates yourself.
Home Assistant VPS requirements and LayerOne cost
| Item | Practical starting point |
|---|---|
| Minimum RAM | 2 GB; this matches Home Assistant's current minimum VM memory guidance |
| Recommended RAM | 4 GB for integrations, recorder/history, update overlap, and modest growth |
| Expected CPU usage | Often about 3–10% of one vCPU for a small settled instance; startup, database purge/repack, templates, cameras, voice, and busy integrations can burst across both vCPUs |
| Storage requirement | 32 GB is a practical floor; 60 GB leaves room for Ubuntu, images, backups, recorder history, media, and updates |
| Exact LayerOne SKU | gc.small (layerone-4g): 2 vCPU, 4 GB RAM, 60 GB disk |
| Expected monthly cost | $0.0109/hour, about $8.00 for 730 hours at the catalog's monthly equivalent |
Camera recording, Frigate, local speech models, large media libraries, and a
high-rate recorder are separate heavy workloads and are not covered by this
baseline. Measure home-assistant_v2.db, backup, media, memory, and CPU growth;
resize the server before it runs out of room.
LayerOne meters the VPS hourly from prepaid credit. The monthly equivalent does not include taxes, optional services, Home Assistant Cloud, extra transfer, or other third-party services. Confirm live catalog values on Pricing.
1. Decide whether a remote VPS fits the smart home
Use a VPS when the devices can be reached through supported cloud APIs, an authenticated site-to-site path, or a carefully designed home-side subnet router. Do not expect multicast discovery such as mDNS or SSDP to cross the public internet. A Tailscale or WireGuard link can provide IP reachability, but it does not automatically carry every broadcast discovery protocol.
If critical lights, locks, alarms, heating, Zigbee, Z-Wave, Thread, Bluetooth, or Matter devices need local radio hardware and offline operation, run Home Assistant OS on hardware at home and use a secure remote-access option instead. This limitation is more important than the VPS plan size.
2. Prepare Ubuntu and install Docker
Complete Your first hour on a new server, then install Docker Engine from its official repository with Docker on a VPS. Confirm Home Assistant's minimum Docker version:
sudo docker version
sudo docker compose version
The server Engine version must be 23.0.0 or newer.
3. Create the official stable Compose service
Create the persistent configuration directory:
sudo install -d -m 0750 /opt/homeassistant/config
cd /opt/homeassistant
Create /opt/homeassistant/compose.yaml, replacing the example time zone with a
valid IANA time-zone name for the home:
sudo tee /opt/homeassistant/compose.yaml >/dev/null <<'YAML'
services:
homeassistant:
container_name: homeassistant
image: ghcr.io/home-assistant/home-assistant:stable
volumes:
- /opt/homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
restart: unless-stopped
stop_grace_period: 60s
privileged: true
network_mode: host
environment:
TZ: America/New_York
YAML
sudo docker compose -f /opt/homeassistant/compose.yaml config
sudo docker compose -f /opt/homeassistant/compose.yaml up -d
sudo docker compose -f /opt/homeassistant/compose.yaml logs --tail=100 homeassistant
The stable image channel follows supported Home Assistant releases. The
official container recipe uses host networking and privileged mode. Privileged
mode gives the container broad control of the VPS, so install only trusted
integrations and do not treat this host as a boundary from Home Assistant.
/run/dbus is optional unless a supported integration needs it; a VPS still
cannot see a USB radio physically located at home.
Home Assistant Container currently listens on TCP 8123. Verify it locally:
curl -sS -o /dev/null -w '%{http_code}
' http://127.0.0.1:8123/
sudo ss -lntp | grep 8123
4. Choose one remote-access design
Do not expose plain TCP 8123 to the internet. Choose either private VPN access or public HTTPS through a reverse proxy.
Option A: private access over Tailscale
Install Tailscale on this VPS and the client devices, but the Home Assistant VPS does not need to advertise itself as an exit node. Allow Home Assistant only on the tailnet interface:
ADMIN_CIDR="198.51.100.24/32"
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from "$ADMIN_CIDR" to any port 22 proto tcp
sudo ufw allow 41641/udp
sudo ufw allow in on tailscale0 to any port 8123 proto tcp
sudo ufw enable
sudo ufw status numbered
In the LayerOne cloud firewall, allow TCP 22 from the administrator CIDR and UDP
41641 publicly, with inbound otherwise DROP. Add no TCP 8123 rule; decrypted
tailnet traffic arrives on the guest's tailscale0 interface. Use a Tailscale
policy that permits only intended users to reach this node on 8123.
Option B: public HTTPS through Caddy
Point a DNS A record such as ha.example.com to the VPS. Install Caddy with
Reverse proxy on a VPS, then use:
ha.example.com {
reverse_proxy 127.0.0.1:8123
}
Home Assistant blocks forwarded requests until the immediate proxy is trusted.
Add this to /opt/homeassistant/config/configuration.yaml:
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
- ::1
ip_ban_enabled: true
login_attempts_threshold: 5
If an http: section already exists, merge these keys; YAML cannot contain two
top-level http mappings. Validate the Home Assistant configuration from
Developer tools, then restart the container:
sudo docker compose -f /opt/homeassistant/compose.yaml restart homeassistant
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
Use these firewall rules for the public-HTTPS design:
ADMIN_CIDR="198.51.100.24/32"
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from "$ADMIN_CIDR" to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 8123/tcp
sudo ufw enable
Mirror TCP 22, 80, and 443 in the LayerOne cloud firewall, and add no rule for 8123. Caddy handles Home Assistant's WebSocket connection automatically.
| Port | Public exposure | Purpose |
|---|---|---|
| TCP 22 | Administrator CIDR only | Host administration |
| TCP 80/443 | Public only for Caddy design | Certificate validation, redirect, and HTTPS UI/API |
| UDP 41641 | Public only for Tailscale design | Direct encrypted tailnet transport |
| TCP 8123 | Never public | Home Assistant backend or tailnet-only service |
5. Complete onboarding and verify from outside
Open the private tailnet URL or https://ha.example.com/ and create the owner
account. Use a strong unique password. From the owner profile's Security
tab, enable multi-factor authentication and review active refresh tokens.
Test from a device that is not on the VPS itself:
curl -I https://ha.example.com/
For the Tailscale design, use the VPS Tailscale name or address and port 8123
instead. Confirm that the dashboard loads live updates, login redirects return
to the right hostname, the Companion app connects, and http://PUBLIC_IP:8123
times out. Test at least one automation end-to-end; a dashboard alone does not
prove a device path works.
6. Bound recorder and backup growth
Home Assistant's recorder writes continuously. Its default automatic purge retains ten days, but noisy entities and media can still grow quickly. Review the official Recorder settings before excluding entities or changing retention:
sudo du -sh /opt/homeassistant/config
sudo find /opt/homeassistant/config -maxdepth 1 -type f -printf '%f %s bytes
' | sort -k2 -n
df -h /
Use Settings → System → Backups to configure automatic encrypted backups, retention, and at least one location outside the VPS. Download the backup emergency kit and store it separately; an encrypted backup without its key is not a recovery plan. Home Assistant Container supports backup and restore, but a local backup under the same VPS is only the first copy.
For an additional cold file copy, stop the container so SQLite is consistent,
archive /opt/homeassistant, restart it, and immediately move the archive off
the server:
sudo docker compose -f /opt/homeassistant/compose.yaml stop homeassistant
sudo tar --acls --xattrs -C /opt -czf "/root/homeassistant-$(date +%F).tar.gz" homeassistant
sudo docker compose -f /opt/homeassistant/compose.yaml start homeassistant
Test restore during onboarding on an isolated instance. LayerOne does not back up the guest disk; read Backups and snapshots.
7. Update the stable container safely
Home Assistant ships frequent releases that can contain backward-incompatible integration changes. Read every relevant release note and create an off-server backup before pulling:
cd /opt/homeassistant
sudo docker compose pull homeassistant
sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=150 homeassistant
Then check Settings → System → Repairs, run an important automation, and
watch logs. Do not switch a production home to beta or dev. If a release
must be pinned, use a documented Home Assistant version tag and retain the
backup required to reverse any data migration.
Security and reliability checklist
- Prefer Home Assistant Cloud or a VPN for remote access when public hosting is not required; never publish plain port 8123.
- Use a unique owner password, multi-factor authentication, and separate non-administrator accounts for household members.
- Trust only the immediate reverse proxy address, not an entire public subnet.
- Keep the
wwwdirectory free of secrets; Home Assistant documents that files served from it are unauthenticated when the URL is known. - Install only reviewed custom integrations because the official container is privileged in this design.
- Keep a local fallback for safety-critical automations when the home internet or VPS route fails.
- Store automatic encrypted backups off-server and protect the emergency kit.
- Monitor recorder size, free disk, memory, integration errors, and external reachability.