How to run Home Assistant Container with Docker on a server
Run Home Assistant Container with Docker Compose on a server, reach it over WireGuard or Caddy HTTPS with trusted proxies, and back up and update it safely.
- Intermediate
- 35 min read
- Updated
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13
On this page
- Prerequisites
- What works on a remote server
- Step 1 — Create the Compose file
- Step 2 — Close the firewall and start Home Assistant
- Step 3 — Onboard through an SSH tunnel
- Step 4 — Trust Caddy as a reverse proxy
- Step 5 — Publish Home Assistant over HTTPS with Caddy
- Step 6 — Reach your home devices over WireGuard
- Back up and restore
- Update Home Assistant
- Troubleshooting
- 400: Bad Request when you open the domain
- Network settings reverted after a few minutes
- Port 8123 cannot be reached from your browser
- Devices at home are not discovered
- Home Assistant does not start after editing configuration.yaml
- Next steps
Home Assistant is an open-source home automation platform with thousands of integrations, a visual automation editor and customisable dashboards. The Home Assistant Container installation runs the core application from the official image ghcr.io/home-assistant/home-assistant with Docker.
Running it on a rented server instead of a box at home changes what it can do: there are no USB radios and no local network to discover devices on. In return you get a hub that is always online, reachable from anywhere, and that can control your home over a VPN. This guide sets up Home Assistant Container with Docker Compose as documented by the project, onboards it through an SSH tunnel, publishes it over HTTPS with Caddy and the required trusted proxy settings, connects it to your home with WireGuard, and covers backups and updates.
Prerequisites
- A server running Ubuntu 24.04 or 26.04 LTS or Debian 12 or 13.
- A non-root user with
sudorights: see Secure a new Linux server and Set up SSH keys. - Docker Engine 23.0.0 or newer with the Compose plugin, from Docker's repository: Ubuntu or Debian. Home Assistant states that Docker Desktop does not work.
- For HTTPS: Caddy from How to set up Caddy as a reverse proxy and a subdomain such as
ha.example.compointing at the server. For access to devices at home: a WireGuard VPN server.
Home Assistant publishes hardware minimums only for the Home Assistant OS virtual machine (2 GB of RAM and 2 vCPUs), not for Container. The suggested values below are a conservative starting point:
| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| RAM | Not published for Container (2 GB for the OS virtual machine) | 2 GB |
| CPU | Not published for Container (2 vCPUs for the OS virtual machine) | 2 vCPUs |
| Disk | Not published for Container | 20 GB SSD; the history database and backups grow over time |
What works on a remote server
| Feature | Home Assistant OS at home | Container on a remote server |
|---|---|---|
| Automations, dashboards, integrations | Yes | Yes |
| Apps (formerly add-ons) and the Supervisor | Yes | No; run extra services as separate containers |
| Backups from the interface | Yes | Yes |
| USB radios (Zigbee, Z-Wave, Thread) and Bluetooth | Yes, with local hardware | No; there is no local hardware |
| Automatic discovery of home devices | Yes, on the home network | No; add devices by IP address over the VPN |
Home Assistant also notes that Thread and Z-Wave are controlled by apps, so Container has no out-of-the-box support for them.
Step 1 — Create the Compose file
Create a project folder with a config subfolder, then the Compose file:
sudo mkdir -p /opt/homeassistant/config
sudo chown -R $USER:$USER /opt/homeassistant
cd /opt/homeassistant
nano compose.yamlPaste the official example with the config path filled in, and set TZ to your time zone:
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: Europe/Amsterdamnetwork_mode: host lets Home Assistant use the server's network directly, which many integrations expect. It also means port 8123 is a normal host port, so ufw does filter it, unlike ports published by Docker.
Step 2 — Close the firewall and start Home Assistant
Allow only SSH so that port 8123 stays closed to the internet, then start the container:
sudo ufw allow OpenSSH
sudo ufw enable
docker compose up -d
docker compose ps
docker compose logs -f homeassistantWait until the log stops showing setup messages, then press Ctrl+C. Check that Home Assistant answers locally:
curl -I http://127.0.0.1:8123
sudo ss -tlnp | grep 8123curl prints HTTP headers, and ss shows Home Assistant listening on all addresses, which ufw now blocks from outside.
Step 3 — Onboard through an SSH tunnel
The first person to open Home Assistant creates the owner account. Do this through a tunnel. On your own computer, run:
ssh -L 8123:127.0.0.1:8123 admin@203.0.113.10Open http://localhost:8123, select Create my smart home, and enter a name, a lowercase username and a strong password. Home Assistant warns that the owner credentials cannot be recovered, so store them in a password manager. Then set your home location, which also sets the time zone, unit system and currency, choose what anonymous data to share (sharing is off by default), and select Finish.
Turn on multi-factor authentication right away: open your user profile, go to the Security tab and enable the authenticator app module.
Step 4 — Trust Caddy as a reverse proxy
Home Assistant blocks requests from reverse proxies unless you allow them. With host networking, Caddy on the same server connects from 127.0.0.1 (or ::1). Since version 2026.8 these settings live in the interface, not in configuration.yaml:
- Go to Settings → System → Network and find the HTTP server section.
- Turn on Trust X-Forwarded-For.
- Add
127.0.0.1and::1to Trusted proxies. - Turn on Enable IP banning and set Login attempts before ban to a low number, such as 5.
- Save. Home Assistant restarts, and you must confirm the new settings afterwards; otherwise it reverts to the previous settings after 5 minutes.
If you upgrade an older installation that still has an http: block in configuration.yaml, Home Assistant imports it into these settings once and then shows a repair asking you to remove the block.
Step 5 — Publish Home Assistant over HTTPS with Caddy
Open the web ports and add a site block to /etc/caddy/Caddyfile. Caddy proxies WebSocket connections, which the Home Assistant frontend uses, without extra settings:
ha.example.com {
reverse_proxy 127.0.0.1:8123
}sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo systemctl reload caddy
curl -I https://ha.example.comYou should get an HTTP response with a valid certificate. Under Settings → System → Network, set the Home Assistant URL for the internet to https://ha.example.com, so links and the companion apps use it.
Step 6 — Reach your home devices over WireGuard
Home Assistant on a server can only control devices it can reach over the network. The usual pattern is a site-to-site VPN: the server runs WireGuard, and a router or small device at home joins as a peer that routes your home subnet, for example 192.168.1.0/24. Set this up with How to set up a WireGuard VPN server, adding the home subnet to that peer's allowed IPs.
From the server, check that a home device answers, then add its integration in Home Assistant by IP address:
ping -c 3 192.168.1.10Automatic discovery (mDNS, SSDP) does not cross a routed VPN, so devices are not found on their own; most integrations let you enter the address manually. You can also use the VPN to open Home Assistant from your phone instead of publishing it with Caddy. Allow the port only on the VPN interface:
sudo ufw allow in on wg0 to any port 8123 proto tcpBack up and restore
Everything Home Assistant knows lives in the config folder, /opt/homeassistant/config: configuration.yaml, the hidden .storage folder with dashboards and integrations, and the history database.
Backups from the interface. Go to Settings → System → Backups, select Backup now and then Manual backup, or set up automatic backups, which also delete old ones. Download the emergency kit and keep it safe; it holds the key you need to restore encrypted backups. On Container, local backups are written to /opt/homeassistant/config/backups, inside the folder they protect, so copy them elsewhere or add a network or cloud backup location in the same screen.
Folder backup. Stop the container, archive the whole config folder, and start it again:
sudo mkdir -p /opt/backups
cd /opt/homeassistant
docker compose stop
sudo tar czf /opt/backups/homeassistant-config-$(date +%F).tar.gz -C /opt/homeassistant config
docker compose startCopy /opt/backups to another machine with rsync or scp.
Restore. In the interface, open Settings → System → Backups, select a backup and choose Restore. On a fresh installation, the welcome screen lets you upload a backup instead of creating a new home. To restore the folder archive, stop the container, move the current folder aside and unpack the archive:
cd /opt/homeassistant
docker compose down
sudo mv config config.old
sudo tar xzf /opt/backups/homeassistant-config-2026-10-09.tar.gz -C /opt/homeassistant
docker compose up -dUpdate Home Assistant
Read the release notes first, especially the Backward-incompatible changes section, and make a backup. Then pull the new image and recreate the container, as the Container documentation describes:
cd /opt/homeassistant
docker compose pull homeassistant
docker compose up -d
docker image pruneAfterwards, check Settings → System → Repairs and the logs. The stable tag always points to the latest stable release. To control updates, replace it with a specific version tag, for example 2026.10.0, which also lets you go back to a previous release.
Before restarting after manual YAML changes, validate the configuration:
docker exec homeassistant python -m homeassistant --script check_config --config /configTroubleshooting
400: Bad Request when you open the domain
Home Assistant does not trust the proxy. Repeat Step 4 and make sure both 127.0.0.1 and ::1 are in the trusted proxies, then check the log with docker compose logs homeassistant for a message about a request from a reverse proxy.
Network settings reverted after a few minutes
After saving the HTTP server settings, Home Assistant restarts and waits for an administrator to confirm them. If nobody confirms within 5 minutes, it restores the previous settings. Save again and confirm.
Port 8123 cannot be reached from your browser
That is intended: ufw blocks it. Use the SSH tunnel, the VPN, or the Caddy domain. If you expected access over WireGuard, check that the wg0 rule exists with sudo ufw status.
Devices at home are not discovered
Discovery protocols do not cross the VPN. Check that the server can reach the device with ping, then add the integration manually with the device's IP address. If ping fails, the home subnet is missing from the WireGuard peer's allowed IPs or the home router does not route it.
Home Assistant does not start after editing configuration.yaml
A YAML error stops the configuration from loading. Run the check_config command from the update section, fix the reported lines, and start the container again with docker compose up -d.
Next steps
- Connect the server to your home network with a WireGuard VPN server.
- Learn more about HTTPS and site blocks in How to set up Caddy as a reverse proxy.
- Add more services as containers with Docker Compose basics.
- Compare servers for home automation on the Home Assistant hosting page.
- Explore integrations in the Home Assistant documentation.
Frequently asked questions
What is the difference between Home Assistant OS and Home Assistant Container?
Home Assistant OS is a complete operating system with the Supervisor, which manages apps (formerly add-ons) and one-click updates. Home Assistant Container is the same core application in a Docker image: it has no apps, and you update it by pulling a new image.
Can I use Zigbee or Z-Wave sticks with Home Assistant on a remote server?
Not directly. USB radios and Bluetooth must be plugged into the machine that runs Home Assistant, and a data-centre server has no access to your home. Use network-based devices and integrations, reached over a VPN to your home network.
Why does Home Assistant return 400 Bad Request behind Caddy?
Home Assistant blocks requests from reverse proxies it does not trust. Open Settings, System, Network, turn on Trust X-Forwarded-For in the HTTP server section and add 127.0.0.1 and ::1 as trusted proxies, then confirm the new settings after the restart.
Does Home Assistant Container support backups?
Yes. The backup integration creates and restores backups on all installation types. On Container, local backups are stored in the backups folder inside the config directory, so copy them off the server or add a remote backup location.
Which HyperDC servers can run Home Assistant?
Home Assistant Container runs on a HyperDC Linux VPS, VDS or dedicated server with root access and Docker Engine 23 or newer. It is most useful there as a central hub for network and cloud integrations reached over a VPN.
Sources
- home-assistant.io/installation/linux
- home-assistant.io/installation
- home-assistant.io/integrations/http
- home-assistant.io/getting-started/onboarding
- home-assistant.io/common-tasks/container
- home-assistant.io/common-tasks/general
- home-assistant.io/integrations/backup
- raw.githubusercontent.com/home-assistant/core/dev/homeassistant/com…