Home Assistant in Docker with Nginx and Let's Encrypt on Raspberry Pi
This guide will help to you to setup home assistant as a docker container and make it publicly available behind a ngix proxy, all running in containers. Additionally, we'll use certbot to keep your ssl certificates in sync and Duck DNS so that you access it even with a dynamic ip address.
![]() |
There we go... Dockerized Home Assistant behind Nginx with Let's Encrypt and DuckDNS :) |
This guide is partially based on the generic guide on how to install Ngix and Let's Encrypt by Philipp (Nginx and Let’s Encrypt with Docker in Less Than 5 Minutes | by Philipp | Medium)
In order to start, please make sure you have the following setups done already
- Home Assistant installed as docker container and available under port 8123
- Create a DuckDNS account and register your subdomain
- You know how to redirect a port from your router to the computer running docker
Let's get SSL started!
version: '3'
services:
nginx:
image: arm64v8/nginx
ports:
- "80:80"
volumes:
- ./data/nginx:/etc/nginx/conf.d:ro
- ./data/wwwroot:/var/www/root:ro
- docker-compose.yaml: The file above
- ./data/nginx: The configuration for nginx, basically the file app.conf
- ./data/wwwroot: content of the default bindings (port 80 and 443), like an index.html
Make Nginx available from internet
server {
listen 80;
server_name yourdomain.duckdns.org; #replace this
location / {
root /var/www/root;
}
}
<html>
<body>
<h1>Welcome</h1>
It works!
</html>T
ubuntu@rpiuntu:/home/docker/proxy$ tree
.
├── data
│ ├── nginx
│ │ └── app.conf
│ └── wwwroot
│ └── index.html
└── docker-compose.ymlT
Use docker-compose up to start and see the log in the command line. Exit with Ctrl-C.
![]() |
Using visualping.io to check accessibility from remote |
Switch to SSL
version: '3'
services:
nginx:
image: arm64v8/nginx
ports:
- "80:80"
- "443:443" # added
volumes:
- ./data/nginx:/etc/nginx/conf.d:ro
- ./data/wwwroot:/var/www/root:ro
- ./data/certbot/conf:/etc/letsencrypt:ro # added
- ./data/certbot/www:/var/www/certbot:ro # added
certbot: # added
image: certbot/certbot:arm64v8-latest # added
volumes: # added
- ./data/certbot/conf:/etc/letsencrypt # added
- ./data/certbot/www:/var/www/certbot # added
- ./data/certbot/conf: All the configuration for the certbot
- ./data/certbot/www: Public accessible challenges folder
- Serves the challenges under the challenges folder when asked
- Serves the index.html under port 443 with ssl and the given certificates
server {
listen 80;
server_name yourdomain.duckdns.org; # replace this
location /.well-known/acme-challenge/ { # added
root /var/www/certbot; # added
} # added
location / {
root /var/www/root;
}
}
server {
listen 443 ssl;
server_name yourdomain.duckdns.org;
location / {
root /var/www/root;
}
ssl_certificate /etc/letsencrypt/live/##REPLACE##/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/##REPLACE##/privkey.pem;
#Optional: Only works with Philipp's script (see below)
include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
- Comment out the second server and wait until certificates are downloaded via certibot
- Use the script from Philipp's Article which generates a temporary certificate for the first start
- Download the script
- Edit the script to include your domain and e-mail address
- Run the script
Setup Certificate Renewal
entrypoint: "/bin/sh -c 'trap exit TERM; while :;
do certbot renew; sleep 12h & wait $${!}; done;'"
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!};
nginx -s reload; done & nginx -g \"daemon off;\
version: '3'
services:
nginx:
image: arm64v8/nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./data/nginx:/etc/nginx/conf.d:ro
- ./data/wwwroot:/var/www/root:ro
- ./data/certbot/conf:/etc/letsencrypt:ro
- ./data/certbot/www:/var/www/certbot:ro
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot:arm64v8-latest
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Update DuckDNS Entries automatically
version: '3'
services:
duckdns:
image: lscr.io/linuxserver/duckdns:latest
environment:
- TZ=Asia/Singapore
- SUBDOMAINS=##REPLACE##
- TOKEN=##REPLACE##
- LOG_FILE=true
volumes:
- ./duckdns:/config
restart: unless-stopped
Make Home Assistant Available via Reverse Proxy
nginx and docker
server {
listen 443 ssl;
server_name yourdomain.duckdns.org;
location / {
proxy_pass http://127.0.0.1:8123; #YOUR Address and Port of HA
proxy_set_header Host $host;
proxy_redirect http:// https://;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
ssl_certificate /etc/letsencrypt/live/##REPLACE##/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/##REPLACE##/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
version: '3'
services:
nginx:
image: arm64v8/nginx
ports:
- "80:80"
- "443:443"
- "8124:8124"
Home Assistant
- Make sure Home Assistant can identify the IP of the client
- Allows the revers proxy to connect to the endpoint
# Loads default set of integrations. Do not remove.
default_config:
# Text to speech
tts:
- platform: google_translate
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
http:
use_x_forwarded_for: true # How to extract client IP address
trusted_proxies: # Permit connections from reverse proxy
- 172.16.0.0/12
Thanks a lot for this great tutorial, it works as a charm!
ReplyDeleteThansk for you feedback, great to hear!
DeleteUnfortunately this didn't work for me... I'm able to create the https test website but when I try the home assistant integration, I get "This site can’t provide a secure connection" in my browser and in the HA logs: from: Logger: aiohttp.server... Any thoughts?
ReplyDeleteNevermind, got it working. I replaced the IP in proxy_pass http://127.0.0.1:8123 with my LAN IP, 192.168.xxx.xxx I also restarted the NGINX container
DeleteI think "listen 443 ssl" should be "listen 8124 ssl" if 8124 port is used.
ReplyDeleteHi, thanks for this guide it works really well. I am trying to add vscode server to the mix but it gives me some errors with the websocket (1006 error). Is there someone who succeeded in getting it working with vscode server too?
ReplyDelete