Shoutout @del13r for posting a great tutorial on the community forum and indepth feedback on GitHub issues.
Ecowitt can only send stats to HTTP API endpoints and we want to keep our Home Assistant secure via HTTP/s access only.
Run a docker container on home assistant that restarts automatically*
*I'm running it on the same server as Home Assistant, but it can be ran anywhere on anything running nginx.
- docker
- host (home assistant)
- Can limit traffic modification to HTTPS endpoint
- Can restrict traffic by IP (even locally) or IP range
- Can enforce nginx HTTPS/SSL validation on the HTTPS endpoint connection
- Doesn't require Home Assistant changes
- Easy to tweak to match your security model, know what's running (where and why!)
Create NGINX Configuration File
mkdir -p ~/nginx-reverse-proxy
Create the NGINX configuration template
cat <<'EOF' > ~/nginx-reverse-proxy/nginx.conf.template
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off; # disable sharing the nginx version
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
server_name localhost;
location / {
allow ${ECOWITT_GW1000_IP}; # Replace with your allowed IP
deny all; # Deny all other IPs
proxy_pass https://${PROXY_SERVER_IP}:${PROXY_SERVER_PORT}${PROXY_PATH};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_ssl_verify off; # Use with caution
proxy_ssl_server_name on;
proxy_ssl_protocols TLSv1.3;
proxy_ssl_session_reuse on;
proxy_http_version 1.1;
}
}
}
EOF
# export env vars
export PROXY_SERVER_IP="external-url-or-internal-ip.ui.nabu.casa"
export PROXY_PATH="/api/webhook/9asd82kmf8vh23iyam3f9"
export PROXY_SERVER_PORT="443"
# or range to test (ie: 192.168.7.0/24)
export ECOWITT_GW1000_IP='192.168.7.163'
Create a final NGINX configuration file from the template
When you tell envsubst
exactly which variables to swap (like $PROXY_SERVER_IP
, $PROXY_PATH
, $PROXY_SERVER_PORT
, $ECOWITT_GW1000_IP
), it only replaces those and leaves the remaing variables alone. This lets us tweak just what we need without messing up the other settings that Nginx needs to do its thing.
envsubst '$PROXY_SERVER_IP,$PROXY_PATH,$PROXY_SERVER_PORT,$ECOWITT_GW1000_IP' < ~/nginx-reverse-proxy/nginx.conf.template > ~/nginx-reverse-proxy/nginx.conf
Run NGINX Docker Container
# Run the NGINX Docker container with the final configuration
docker run -d --name nginx-reverse-proxy-container \
--restart unless-stopped \
-p 1337:80 \
-v ~/nginx-reverse-proxy/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:latest
Check if it's up:
# docker ps
# check logs by id
# docker logs ID
One major downside to running it on my managed Home Assistant, I get the message that I'm running unsupported software:
I'm going to yolo ignore it for now and see how things go. Many folks have said this is ok and updates will not stop, I just cannot expect support to provide support for my customizaitons. That's fair!
Looking at the logs from the nginx reverse proxy, I see that I'm POSTing 2 bytes per minute to my external HTTPS endpoint.
At 2 bytes per minute over the internet, i'll send approximately 87,667 bytes (about 87.7 kilobytes) of data on average per month.
I would like to validate the SSL via nginx with something like: https://stackoverflow.com/questions/66111292/nginx-proxy-ssl-trusted-certificate-with-letsencrypt-upstream
But, thinking "what if" the backend was redirect malicously, it would be able to intercept 2 bytes of my environment post / body data and not really much more.
It might be worth it to try later.
# Download the Certificates
You can download the Let's Encrypt certificates using the curl command. The URLs for the root and intermediate certificates can be found on the Let's Encrypt website or through their documentation. As of my last update, you can use the following commands:
# Download the ISRG Root X1 Certificate
curl -o isrgrootx1.pem https://letsencrypt.org/certs/isrgrootx1.pem
# Download the Let’s Encrypt R3 Intermediate Certificate
curl -o letsencrypt-r3.pem https://letsencrypt.org/certs/lets-encrypt-r3.pem
# Combine the Certificates into a Bundle
cat isrgrootx1.pem letsencrypt-r3.pem > letsencrypt-ca-bundle.pem
# Configure Nginx
#proxy_ssl_trusted_certificate /path/to/your/letsencrypt-ca-bundle.pem;
#proxy_ssl_verify on;
#proxy_ssl_verify_depth 2;
Shows that we can hit the api endpoint, but it's a GET not a POST - so it's Not Allowed
% curl -vvv 192.168.7.139:1337/
* Trying 192.168.7.139:1337...
* Connected to 192.168.7.139 (192.168.7.139) port 1337 (#0)
> GET / HTTP/1.1
> Host: 192.168.7.139:1337
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 405 Method Not Allowed
< Server: nginx
< Date: Wed, 20 Dec 2023 15:28:31 GMT
< Content-Type: application/octet-stream
< Content-Length: 0
< Connection: keep-alive
< Referrer-Policy: no-referrer
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
<
* Connection #0 to host 192.168.7.139 left intact