Home Assistant一般安装好之后都是需要通过公网来访问使用的,而Home Assistant的Web端默认只提供http访问,肯定不如https让人放心,这里一般就是用反向代理来实现了。

方案选定

我是使用frp将本地Home Assistant的Web端口(默认8123),映射到公网主机的8080端口。之前一直是裸奔的http,但是毕竟不安全,需要升级一下。有以下几个方案备选

  • frp本身支持将http流量转化为https。但是我觉得有些麻烦,因为证书需要在本地frpc设置好。但是我的证书每个月定时在服务器上更新(acme.sh定时任务)。
  • Home Assistant通过NGINX Home Assistant SSL proxy这个Adds-on,可以在本地实现反向代理。因为我的本地客户端没有公网IP,若配置证书只能用远程服务器的域名和证书,原因同上,维护起来太麻烦。
  • frp将流量转发到公网主机的8081端口,再由公网主机上的Nginx反向代理8081端口,并监听8082端口提供https服务。因为我已经在公网主机的Nginx上配置过TLS证书的每月自动更新,这个方法可以让我免维护。

综上所述,我选择frp内网穿透+nginx反向代理的方式来完成https访问homeassistant的管理页面。示意图如下:
diagram

配置过程

前提条件:我远程服务器的域名是yangbo.party,已经按照之前的博文Xray配置Vless-Reality-Vision配置好Nginx和证书。

公网服务器配置

先配置frps的配置文件/etc/frp/frps.toml

1
2
3
4
bindPort = 7000
webServer.port = 7001
webServer.user = "admin"
webServer.password = "xxxxx"

其中frp的后台管理密码自行设定。
再配置Nginx的配置文件/etc/nginx/nginx.conf,因为之前已经配置好了,所以在之前的基础上加入新的server字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server {
listen 8082 ssl fastopen=3;
server_name yangbo.party;

# SSL 配置
ssl_certificate /root/.acme.sh/yangbo.party_ecc/yangbo.party.cer;
ssl_certificate_key /root/.acme.sh/yangbo.party_ecc/yangbo.party.key;

# 推荐的 SSL 安全设置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

# 安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";

location / {
proxy_pass http://127.0.0.1:8081;

# 保留原始请求信息
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;

# WebSocket 支持(HomeAssistant 需要)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# 超时设置
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}

全部配置好可以重启两个程序:systemctl restart nginx && systemctl restart frps && echo 'OK'

本地客户端配置

HomeAssistant会验证Host头,当127.0.0.1作为代理服务器时,Home Assistant默认不信任它提供的代理头信息,而我们利用Nginx做反向代理时就是监听127.0.0.1。同时暴露在公网也要防止别人暴力破解密码。所以Home Assistant需要修改一下配置,打开configuration.yaml,添加以下内容:

1
2
3
4
5
http:
use_x_forwarded_for: true
trusted_proxies: 127.0.0.1
ip_ban_enabled: true
login_attempts_threshold: 100

修改后手动重启Home Assistant
本地frpc的配置文件/etc/frp/frpc.toml:

1
2
3
4
5
6
7
8
9
10
11
serverAddr = "yangbo.party"
serverPort = 7000

[[proxies]]
name = "homeassistant"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8123
remotePort = 8081
transport.useEncryption = true
transport.useCompression = true

这里启用了frp的自定义TLS协议加密,来保障内网穿透过程的信息安全。
配置好可以重启frpc程序:systemctl restart frpc && echo 'OK'

调试

如果一切顺利,这个时候浏览器访问https://yangbo.party:8082就可以访问内网的Home Assistant了。若不行,可以直接测试nginx监听的8082端口是否可以访问:curl -vk https://127.0.0.1:8082或检查frps转发的8081端口是否可以访问:curl -vk http://127.0.0.1:8081或者查看端口占用情况:ss -tulnp