In light of the recent “hacking” stories, last week I set myself the goal of implementing Nginx. I read most related posts in this forum and elsewhere, but was unable to find a step by step guide for “enthusiasts” with limited it skills. Therefore I proceeded to do it the hard way: read, trial and error.
Regretfully the forum was of no use as some of the individuals with “apparent subject matter experience” chose to offer condescending advice with no real benefit or substance. I do, however, want to thank @Ludeeus as he patiently helped me diagnose the multiple bugs I was self-inflicting.
Anyway, on the subject this is how I got it working:
OS: Ubuntu 18.04LTS Running Docker. If you’re not running Docker, I would encourage you to use it; even if only for this.
I have attempted listing all the steps (that worked) and in the process may make some assumptions on what you have. I’m far from an expert, but feel free to ask if stuck.
Use this container: https://hub.docker.com/r/linuxserver/swag
In short its fantastic. It combines Nginx and Letsencrypt. Once run, it creates all the default files, directories, ssl certificates and dependencies that you may need. If you want to expose multiple components securely i.e. configurator, terminal, grafana, etc. It creates an SSL with Subject Alternative Name. What this means is that the one certificate will be good for all the sub-subdomains you want to use. A little explanation on that, since I was confused with it and no doubt there will be others.
Example: https://configurator.mydomain.duckdns.org
##########sub-subdomain.subdomain.domain.tld
Therefore you can create numerous sub-subdomains. Below find my process:
- You will need deactivate ssl in any enabled components starting with home assistant itself: for example
http:
api_password: !secret http_password
#ssl_certificate: /certs/ fullchain.pem
#ssl_key: /certs/privkey.pem
ip_ban_enabled: true #blocks unathorized ips from accessing HA
login_attempts_threshold: 5 #number of attempts before ip is banned
base_url: hass.mydomain.duckdns.org
- Please read the instructions in Docker. It’s 5 minutes and will help understand the process below
- Forward your router ports 80 to 80 and 443 to 443
- Establish the docker user - PGID= and PUID=.
The command is $ id dockeruser.
Output will be 4 digits, which you need to add in these variables respectively
- Create a host directory to support persistence. For example:
- /home/user/docker/swag/config:/config
- Run the following command line or use the docker compose file
docker create
–cap-add=NET_ADMIN
–name=letsencrypt \
-v /home/user/docker/swag/config:/config \
-e PGID= -e PUID= \
-e EMAIL= [email protected]
-e URL=mydomain.duckdns.org
-e SUBDOMAINS=hass,sub1,sub2
-e VALIDATION=http
-p 80:80 -p 443:443
-e TZ=XXX/XXX \
linuxserver/letsencrypt
(get your timezone from here List of tz database time zones - Wikipedia)
Sample docker-compose
swag:
image: linuxserver/swag
container_name: swag
restart: unless-stopped
cap_add:
- NET_ADMIN
volumes:
- /etc/localtime:/etc/localtime:ro
- /home/user/docker/swag/config:/config
environment:
- PGID=1004
- PUID=1000
- [email protected]
- URL=mydomain.duckdns.org
- SUBDOMAINS=hass,sub1,sub2
- VALIDATION=http
- TZ=XXX/XXXX
ports:
- "80:80"
- "443:443"
You must pick at least one subdomain, which will represent home assistant. (in this example hass). So once it’s running HA will be, for example, in https://hass.mydomain.duckdns.org
Once you run the container, you’ll need to edit the default file at (example) home/user/docker/swag/config/nginx/site-confs/default
Some notes on this:
I. Make sure you comment out the following lines in the server blocks.
auth_basic "Restricted"#; auth_basic_user_file /config/nginx/.htpasswd;
These lines will enforce password protection from Nginx and when you try to login you will not be able. You may need to activate this for some component. For instance the configurator component, for some reason will no longer follow its settings file and once live you’ll be able to access it without password. So you’ll need to create an Nginx user:password with this command: docker exec -it letsencrypt htpasswd -c /config/nginx/.htpasswd .
II. Next tip took me a while to discover/resolve. There’s a separate proxy.conf file in
home/user/docker/swag/config/nginx/proxy.conf
the proxy serever blocks include by default the below line which calls this file:
include /config/nginx/proxy.conf;
It worked right away with 8 other components but NOT with Home Assistant. After much reading it turns out that Home Assistant’s “handshake” is different etc, etc, and therefore the proxy configuration is different. So the server block for Home Assistant is different to the other 3 examples below. Basically I commented out the reference to the default proxy.conf file and inserted the specific configuration in the server block itself.
Below find my file (this would replace default nginx/default.conf)
You need to edit all sections containing “mydomain.duckdns.org” as well as “fastcgi_pass hostip:9000;” and “proxy_pass http://hostip:XXXX;”
Once done. Restart the container and you should be able to see https://hass.mydomain.duckdns.org; https://conf.mydomain.duckdns.org; etc
default.conf
## Version 2018/04/20 - Changelog: https://github.com/linuxserver/docker-letsencrypt/commits/master/root/defaults/default
# listening on port 80 disabled by default, remove the "#" signs to enable
# redirect all traffic to https
#server {
# listen 80;
# server_name _;
# return 301 https://$host$request_uri;
#}
################################################################################
#### PORT 80 ACTIVE ############################################################
# listening on port 80 disabled by default, remove the "#" signs to enable
# redirect all traffic to https
server {
listen 80;
server_name mydomain.duckdns.org;
return 301 https://$host$request_uri;
}
################################################################################
################################################################################
# main server block
server {
listen 443 ssl default_server;
root /config/www;
index index.html index.htm index.php;
server_name mydomain.duckdns.org;
# enable subfolder method reverse proxy confs
include /config/nginx/proxy-confs/*.subfolder.conf;
# all ssl related config moved to ssl.conf
include /config/nginx/ssl.conf;
client_max_body_size 0;
location / {
try_files $uri $uri/ /index.html /index.php?$args =404;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# With php7-cgi alone:
fastcgi_pass hostip:9000;
#fastcgi_pass 127.0.0.1:9000;
# With php7-fpm:
#fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
}
# sample reverse proxy config for password protected couchpotato running at IP 192.168.1.50 port 5050 with base url "cp"
# notice this is within the same server block as the base
# don't forget to generate the .htpasswd file as described on docker hub
# location ^~ /cp {
# auth_basic "Restricted";
# auth_basic_user_file /config/nginx/.htpasswd;
# include /config/nginx/proxy.conf;
# proxy_pass http://192.168.1.50:5050/cp;
# }
}
# sample reverse proxy config without url base, but as a subdomain "cp", ip and port same as above
# notice this is a new server block, you need a new server block for each subdomain
#server {
# listen 443 ssl;
#
# root /config/www;
# index index.html index.htm index.php;
#
# server_name cp.*;
#
# include /config/nginx/ssl.conf;
#
# client_max_body_size 0;
#
# location / {
# auth_basic "Restricted";
# auth_basic_user_file /config/nginx/.htpasswd;
# include /config/nginx/proxy.conf;
# proxy_pass http://192.168.1.50:5050;
# }
#}
################################################################################
### SUBDOMAIN 1 ##################################################################
server {
listen 443 ssl;
root /config/www;
index index.html index.htm index.php;
server_name sub1.mydomain.duckdns.org;
include /config/nginx/ssl.conf;
client_max_body_size 0;
location / {
# auth_basic "Restricted";
# auth_basic_user_file /config/nginx/.htpasswd;
include /config/nginx/proxy.conf;
proxy_pass http://hostip:5050;
}
}
### SUBDOMAIN 2 ###############################################################
server {
listen 443 ssl;
root /config/www;
index index.html index.htm index.php;
server_name sub2.mydomain.duckdns.org;
include /config/nginx/ssl.conf;
client_max_body_size 0;
location / {
# auth_basic "Restricted";
# auth_basic_user_file /config/nginx/.htpasswd;
include /config/nginx/proxy.conf;
proxy_pass http://hostip:8181;
}
}
### HOMEASSISTANT ##############################################################
server {
listen 443 ssl;
root /config/www;
index index.html index.htm index.php;
server_name hass.mydomain.duckdns.org;
include /config/nginx/ssl.conf;
client_max_body_size 0;
location / {
# auth_basic "Restricted";
# auth_basic_user_file /config/nginx/.htpasswd;
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";
proxy_buffering off;
proxy_ssl_verify off;
# include /config/nginx/proxy.conf;
proxy_pass http://hostip:8123;
}
}
# enable subdomain method reverse proxy confs
include /config/nginx/proxy-confs/*.subdomain.conf;
Edit: March 11, 2019
Since the original post I’ve made a small change to the set-up as a result of the linuxserver guys improving this docker container.
Initially I was adding each subdomain under the - SUBDOMAINS=hass,sub1,sub2 environment variable.
If you’re using duckdns (as I am) you can now pull a wildcard ssl certificante, which does not require you specifying the sub-subdomain.
To clarify: earlier the certificate would be issued for sub-subdomain.mydomain.duckdns.org in line with the Subject Alternative Name (protocol).
with this revised setup your certificate will be issued for **.mydomain.duckdns.org which means you can create new sub-domains which are covered by the “*” (the wildcard) without adding sub-subdomains to the - SUBDOMAINS variable. You only need create the server block in the nginx/default.conf file as before. Hope this helps understanding.
Here’s my updated docker-compose
swag: #https://hub.docker.com/r/linuxserver/swag
container_name: swag
image: linuxserver/swag
restart: unless-stopped
cap_add:
- NET_ADMIN
volumes:
- /home/user/docker/swag/config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- PGID=1004
- PUID=1000
- [email protected]
- URL=mydomain.duckdns.org
- SUBDOMAINS=wildcard
- VALIDATION=duckdns
- TZ=Asia/Dubai
- DUCKDNSTOKEN=XXXXXXXXX (you need to get this from your duckdns account)
ports:
- "180:80"
- "1443:443"
Edit: Sept 13, 2020
On request I’m adding samples from my docker-compose file.
Some dockers use the “deploy/resources” flag. When using this you need to add the following to your docker compose command:
docker-compose --compatibility up -d