yeskery

利用 frp 将 HomeAssistant 从内网映射到公网

HomeAssistant 已经在内网工作很长一段时间,因为只能在内网访问,所以有时候会不太方便。因为家庭宽带一般不会提供公网 IP,所以需要一台可以在公网访问的服务器(VPS 和云服务器均可),一般的服务器都会分配一个公网固定 IP。

最终实现的效果是通过域名(不加端口号)访问部署在内网的 HomeAssistant。以下的教程服务器端在 CentOS 7 中实现,其它 Linux 发行版和 Windows 系统中大同小异,因为用到的工具 frp、Nginx 均提供了 Linux 和 Windows 的支持。在使用中, frp 本身已经是一个反向代理的软件,也可以不使用 Nginx 来做反向代理,但由于 frp 存在的时间不是特别长,且用途有些和谐,导致文档和功能不是很全面。Nginx 是一款高性能、多功能、使用范围极广的反向代理软件,加上本身服务器还使用了 Nginx 代理了网站,所以选择加上 Nginx 做反向代理,至少可以去掉端口号访问。

服务器端 frp 的安装

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。具体可参考:https://github.com/fatedier/frp/blob/master/README_zh.md

下载 frp

https://github.com/fatedier/frp/releases 页面下载最新的发行版,选择合适的版本,Linux 服务器选择带有 linux 版本,其中 386 代表 32 位的操作系统,amd64 代表 64 位的操作系统。例如 CentOS7 64 位的服务器应该选择 frp_0.16.0_linux_amd64.tar.gz 下载,因为 GitHub CDN 托管在亚马逊的云服务器上,且都在国外,经常会发生下载错误或者下载速度慢的情况,建议多尝试一下,或者更换其它网络下载。

解压安装 frp

解压出来的 frp 目录结构为:

  1. └── frp_0.16.0_linux_amd64
  2. ├── frpc
  3. ├── frpc_full.ini
  4. ├── frpc.ini
  5. ├── frps
  6. ├── frps_full.ini
  7. ├── frps.ini
  8. └── LICENSE

其中,需要使用到的是 frpsfrps.inifrps.full.ini 是一个完整的服务器端配置示例,frpcfrpc.inifrpc.full.ini 是客户端的软件和配置文件,这里不需要使用。

因为 frps 是一个可执行的文件,所以不需要再进行安装。

配置服务器端

完整的 frps.ini 配置说明,可以参考 frps.full.ini 或者 https://github.com/fatedier/frp/blob/master/conf/frps_full.ini,这里我们不需要这么多的配置。

  1. [common]
  2. bind_port = 7000
  3. vhost_http_port = 8123
  4. privilege_token = 12345678

这里因为在 https 是使用 Nginx 来做的反向代理,所以在 frp 配置的时候仅仅使用它的 http 服务。如果需要直接使用 frp 的 https 服务,可以将 vhost_http_port 替换为 vhost_https_port。其中 bind_port 是 frp 运行的端口,采用默认的配置就可以了,另外需要注意的是,这里配置的端口,需要设置为外网可以访问,如果外网无法访问这个端口,那么 frp 是无法进行端口映射的。这里的 privilege_token 是 frp v0.11.0 开始支持的特权模式,也可以不设置。

服务器的配置就完成了,接下来可以使用 ./frps -c ./frps.ini 命令启动 frp 服务器端。如果看到类似“Start frps success”字样,就代表启动成功了。

设置自启

Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

因为Supervisor是Python开发的,安装前先检查一下系统否安装了Python2.4以上版本。下面以CentOS7,Python2.7版本环境下,介绍Supervisor的安装与配置步聚:

Supervisor 安装

  1. yum install epel-release
  2. yum install -y supervisor

supervisor没有发布在标准的CentOS源在,需要安装epel源。这种方式安装的可能不是最新版本,但比较方便,安装完成之后,配置文件会自动帮你生成。

默认配置文件:/etc/supervisord.conf,进程管理配置文件放到:/etc/supervisord.d/ 目录下即可,默认日志文件:/tmp/supervisord.log,可以查看进程的启动信息。

配置 frp 的 supervisor 设置

/etc/supervisord.d/ 新建 frp.ini,并输入下面的内容:

  1. [program:frp]
  2. command = /var/opt/frp_0.16.0_linux_amd64/frps -c /var/opt/frp_0.16.0_linux_amd64/frps.ini
  3. autostart = true

command 里的路径修改位你的 frp 解压路径。

启动 supervisor

  1. supervisord -c /etc/supervisord.conf

接着可以通过 supervisorctl 查看、启动、停止、重启 frp 服务。

客户端的 frp 安装

这里的客户端取决于你想在本地运行 frp 的设备,但是有一个前提条件是,这个设备要能访问到 HomeAssistant 服务。这个设备可以是你安装 HomeAssistant 的树莓派、家里的路由器(路由器需要支持)、甚至你也可以安装在你的电脑上。然后在 https://github.com/fatedier/frp/releases 页面下载设备对应的 frp 版本下来。

frp 的配置

配置 frpc.ini

  1. [common]
  2. server_addr = XXXX
  3. server_port = 7000
  4. privilege_token = 12345678
  5. custom_domains = www.yourdomain.com

其中 server_addr 需要修改为服务器的 ip 地址,server_addr 需要修改为服务器 frp 运行的端口,如果前面设置了 privilege_token,这里修改成和上面一样即可,custom_domains 修改为需要访问的域名,请先将这个域名解析到服务器上。

frp 启动

使用命令 ./frpc -c ./frpc.ini 启动 frp 服务,如果能看到类似 ProxyName [http], connect to server [XXX:7000] success! 的字样,则说明客户端 frp 已经和服务器端的 frp 连接好了。

如果此时在服务器上设置的 8123 端口也可以通过外网访问的话,那么这时访问 http://www.yourdomain.com:8123 已经能够看到 HomeAssistant了。

Nginx 设置

因为 HomeAssistant 采用了 WebSocket 技术,所以除了静态页面之外,其余的操作都需要使用 WebSocket。所以需要在 Nginx 代理转发的时候也配置好 WebSocket。

关于 HomeAssistant 的 WebSocket API 介绍,可以参考:https://home-assistant.io/developers/websocket_api/。在 https://home-assistant.io/developers/api/ 可以看到 HomeAssistant 的所有支持的 API 介绍。

下面是一个示例:

  1. server {
  2. listen 80;
  3. server_name www.yourdomain.com;
  4. location / {
  5. rewrite ^ https://www.yourdomain.com$request_uri? permanent;
  6. }
  7. }
  8. server {
  9. listen 443;
  10. server_name www.yourdomain.com;
  11. ssl on;
  12. ssl_certificate fullchain.pem;
  13. ssl_certificate_key privkey.pem;
  14. ssl_trusted_certificate chain.pem;
  15. ssl_session_timeout 5m;
  16. ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  17. ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
  18. ssl_prefer_server_ciphers on;
  19. proxy_set_header X-Forwarded-For $remote_addr;
  20. gzip on;
  21. gzip_min_length 1k;
  22. gzip_buffers 4 16k;
  23. #gzip_http_version 1.0;
  24. gzip_comp_level 5;
  25. gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  26. gzip_vary off;
  27. gzip_disable "MSIE [1-6]\.";
  28. location /api/websocket {
  29. proxy_pass http://127.0.0.1:8123/api/websocket;
  30. proxy_read_timeout 60s;
  31. proxy_set_header Host $host;
  32. proxy_set_header X-Real_IP $remote_addr;
  33. proxy_set_header X-Forwarded-for $remote_addr;
  34. proxy_http_version 1.1;
  35. proxy_set_header Upgrade $http_upgrade;
  36. proxy_set_header Connection 'Upgrade';
  37. access_log /var/log/nginx/www.yourdomain.com/access.log;
  38. error_log /var/log/nginx/www.yourdomain.com/error.log;
  39. }
  40. location / {
  41. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  42. proxy_set_header Host $http_host;
  43. proxy_buffering off;
  44. proxy_pass http://127.0.0.1:8123;
  45. access_log /var/log/nginx/www.yourdomain.com/access.log;
  46. error_log /var/log/nginx/www.yourdomain.com/error.log;
  47. }
  48. }

本文参考以下内容:

  1. https://www.cnblogs.com/weidiao/p/7389744.html
  2. https://segmentfault.com/a/1190000009353002
  3. https://github.com/fatedier/frp/blob/master/README_zh.md

评论

发表评论 点击刷新验证码

提示

该功能暂未开放