登录后台

页面导航

本文编写于 2407 天前,最后修改于 1430 天前,其中某些信息可能已经过时。

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 目录结构为:

└── frp_0.16.0_linux_amd64
    ├── frpc
    ├── frpc_full.ini
    ├── frpc.ini
    ├── frps
    ├── frps_full.ini
    ├── frps.ini
    └── 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,这里我们不需要这么多的配置。

[common]
bind_port = 7000
vhost_http_port = 8123
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 安装

yum install epel-release
yum install -y supervisor

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

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

配置 frp 的 supervisor 设置

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

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

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

启动 supervisor

supervisord -c /etc/supervisord.conf

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

客户端的 frp 安装

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

frp 的配置

配置 frpc.ini

[common]
server_addr = XXXX
server_port = 7000
privilege_token = 12345678
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 介绍。

下面是一个示例:

server {
  listen       80;
  server_name  www.yourdomain.com;

  location / {
    rewrite ^ https://www.yourdomain.com$request_uri? permanent;
  }
}

server {
  listen 443;
  server_name  www.yourdomain.com;
  ssl on;
  ssl_certificate fullchain.pem;
  ssl_certificate_key privkey.pem;
  ssl_trusted_certificate chain.pem;
  ssl_session_timeout  5m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
  ssl_prefer_server_ciphers   on;
  proxy_set_header X-Forwarded-For $remote_addr;

  gzip on;
  gzip_min_length 1k;
  gzip_buffers 4 16k;
  #gzip_http_version 1.0;
  gzip_comp_level 5;
  gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  gzip_vary off;
  gzip_disable "MSIE [1-6]\.";

  location /api/websocket {
    proxy_pass http://127.0.0.1:8123/api/websocket;
    proxy_read_timeout 60s;
    proxy_set_header Host $host;
    proxy_set_header X-Real_IP $remote_addr;
    proxy_set_header X-Forwarded-for $remote_addr;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'Upgrade';
    access_log /var/log/nginx/www.yourdomain.com/access.log;
    error_log /var/log/nginx/www.yourdomain.com/error.log;
  }

  location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
                proxy_buffering off;
        proxy_pass http://127.0.0.1:8123;

        access_log      /var/log/nginx/www.yourdomain.com/access.log;
        error_log       /var/log/nginx/www.yourdomain.com/error.log;
  }
}

本文参考以下内容:

  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