- Published on
如何给本地开启的 API 服务使用上 HTTPS
一些背景知识
后端开发中,各种 API 服务(比如,Django, Flask, Express.js)启动的时候,一般默认监听的都是127.0.0.1
地址。
如果要使用DHCP
分配的 IP 地址访问,可以把 host 改为0.0.0.0
再启动 API 服务。这样同局域网的主机,比如说前端的同事就可以通过你的 IP 地址访问后端 API 了。
0.0.0.0
的意思是分配给改主机的所有可能的 IPv4 地址。IPv6 是::/0
。
可能分配给主机的 IP 地址是未知的,但是你启动 API 的时候是需要绑定一个 IP 地址的,如果你没有分配到 IP 地址,这个时候127.0.0.1
就有用了,或者localhost
也可以。
如果启动 API 的时候绑定不是你主机的 IP 会怎样?
你应该会有绑定失败,Django 会抛出这个错误: Error: That IP address can't be assigned to.
所以,0.0.0.0
就是有点类似通配符的效果。不需要指定 Hard code 未知的地址。
竟然 0.0.0.0 这么方便,那些 API 框架怎么默认不使用?
我觉得是为了安全,0.0.0.0
会直接让你服务器可能直接暴露在公网里面。一般开发过程中都是没有什么认证措施的,这个时候附近有个人端口扫描一下,可能就会泄露重要的资料。
为什么有了这个文章?
近期空闲时间在写 Side project,需要暴露自己的 API 服务在公网,给一个 Twilio 服务回调我的 API。
当然是可以用 ngrok,但是对比于 4 年前,这个服务现在越来越抠门。以前是可以单机多开,而且不限时长,现在玩了付费订阅制之后,限制越来越多。
我的解决方案是:
- API 服务监听
0.0.0.0
端口,给路由器访问。 - 路由器做端口转发,让宽带公网 IP 的某个端口映射到本机 API 服务端口。
- 为什么不使用路由器 DMZ?
- DMZ 会直接暴露本机到公网。只使用端口转发所需的服务,这样安全点。
最后对公网给 Twilio 的 Callback URL 会是这样 http://58.123.123.123:8000/
。
延伸一下,本地服务 API 服务使用上 HTTPS,而不是直接用本机公网地址?
方案一 AWS API Gateway Proxy
Twilio Callback URL => AWS API Gateway => Your Router Public IP => Router Port forwarding => API (Listen 0.0.0.0)
- AWS API Gateway 会给你分配一个 HTTPS 地址,你需要创建一个 Stage 才会有。
- 直接创建一个 Resource,然后把所有路由都转发到本机的公网 IP,比如上述的
http://58.123.123.123:8000/
- 如果你不想使用 AWS API Gateway 分配的域名,你可以使用 AWS ACM 认证域名,然后在 API Gateway 创建一个漂亮的 custom domain。
- 重要的是,上述的 1 2 3 都是免费的。如果超出了 AWS free tier 期限,AWS API Gateway 是按需付费,零星的使用量基本上是免费的。
- ⚠️ 这个不是全程加密,API Gateway 到本机的 API 服务之间的通信没有使用 HTTPS。
方案二 AWS EC2 Apache 反向代理 + SSH 远程转发(这个是我写这篇文章的时候想到的方法 😂)
Twilio Callback URL => My Wordpress site EC2 Apache Reverse Proxy => SSH Remote forwarding => API (Listen on localhost)
- ✅ 这个是全程加密通信。
- SaaS 到 Apache 是 HTTPS,我还启用了 Http2.0
- Apache 到我本机的 API 服务是 SSH。
- Apache 的反向代理可以使用二级域名,然后创建一个 VirtualHost。
- SSH 使用的是远程转发。因为要远程主机访问本机服务,本机没有公网 IP。
Apache VirtualHost 代码:
<VirtualHost \_default\_:443>
# 一个新的二级域名,记得配置DNS,还有SSL/TLS证书
ServerName xx.adamliu.net
SSLEngine on
SSLCertificateFile "/opt/bitnami/apache2/conf/adamliu.net.crt"
SSLCertificateKeyFile "/opt/bitnami/apache2/conf/adamliu.net.key"
Protocols h2 h2c http/1.1
ProxyPass "/" "http://localhost:8000/"
# 这句是让 3xx 之类的重定向地址可以被 Apache 捕获然后修改为 Apache 的对外URL
ProxyPassReverse "/" "http://localhost:8000/"
# Error Documents
ErrorDocument 503 /503.html
</VirtualHost>
本地电脑需要启用 SSH 远程端口转发:
# ServerAliveInterval 和 ServerAliveCountMax 是为了保持 session 常驻
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=5 -R localhost:8000:localhost:8000 ubuntu@18.123.123.123
完。