Skip to content
+1 (813) 212-3723 support@layeronecloud.com
Self-hosting VPS guides

How to Run Home Assistant on a VPS with Docker

Deploy Home Assistant Container on an Ubuntu VPS with exact sizing, Docker Compose, private or Caddy HTTPS access, firewall rules, backups, and safe updates.

8 min read

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 www directory 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.

Official references

Still stuck

Chat with us from the portal.

Ask the assistant from the Chat bar. During business hours you can ask for a person and a human joins live.