我們經常有在外網訪問我們本地服務的需求,特別是在開發調試階段,比如做微信登錄或者微信支付的時候就需要使用外網正式的域名,然而我們很多時候都是在本地進行開發,我們不可能頻繁的部署到外網環境去進行測試,因為這樣效率太低了,這是我們開發會經常面臨的一個問題。
對於這個問題有很多常用的內網穿透方案,今天我們來為大家介紹的是一個名為 inlets 的工具,該工具是 Go 語言編寫的,之前發佈的時候在 Hacker News 上非常受歡迎,現在 GitHub 上有 4000 多個 Star,接下來我們就來了解下如何使用 inlets 來訪問我們的內網服務。
解決方案
上面我們提到了,對於該問題已經有好幾種比較優秀的解決方案,他們在外部網絡和我們本地環境(無論是 Raspberry Pi,還是家用電腦或者筆記本都可以)之間建立了一條隧道。
下圖是 inlets 的運行原理示意圖:

inlets
一樣的 inlets 的目標是將你的本地服務暴露到 Internet 上面去。
需要的一些材料清單:
- 一個出口節點服務器 - 該這節點可以訪問互聯網和公網 IP,我們的用戶將連接到該節點,並通過 websocket 隧道路由到防火牆內部的本地服務。
- 一個客戶端 - 客戶端充當反向代理或者網橋,當它監聽到請求時,會代理到本地服務(比如 Django 服務器),然後發送一個相應回去。
- 使用 websocket 的隧道 - 大多數公司防火牆允許使用 CONNECT 消息在現有的 HTTP/S 代理上建立出站 TCP 鏈接。
出口節點上的每個 HTTP 請求都會被序列化並作為控制消息發佈到 websocket 上面去,然後阻塞住。然後,客戶端接收這些請求,確定其是否知道如何代理該站點,然後獲取資源並將其作為序列化響應發送回 websocket。
最後,用戶的 HTTP 請求將解除阻塞並將相應寫入調用方,這樣就完成了整個調用過程。
默認情況下,對於開發 inlets 是被配置為使用非加密隧道,這樣的話就很容易受到攻擊,我們可以啟用 HTTPS 來進行通信,比如使用 Caddy。
使用
對於出口節點我們可以使用阿里雲或者其他雲服務器,甚至更便宜的 VPS 也可以,主要要求是我們必須具有帶有公網 IP 的服務器即可。

比如我們這裡有一臺公網 IP 為 1.2.3.4 的節點,使用域名 exit.qikqiak.com 來進行內網服務代理,為該域名創建一個 A 記錄,解析到公網 IP 上面。
inlets 控制端的安裝有多種方式方法,只需要能夠綁定到 80 和 443 端口即可,比如 Nginx、Caddy 都可以,我們這裡使用 Kubernetes Ingress 的方式來暴露 inlets 的控制端程序。
如果你的節點上沒有 Kubernetes 集群,也可以直接 Docker 運行,更多信息可以查看 https://github.com/alexellis/inlets 瞭解更多信息。
首先需要保證你集群中已經安裝了 Ingress Controller,並且要在我們上面的這個出口節點部署對應的 Pod,我們這裡已經部署使用了 Traefik 2.0 版本。接下來就是部署 inlets 控制端程序。
- 創建一個隨機的 secret
kubectl create secret generic inlets-token --from-literal token=$(head -c 16 /dev/urandom | shasum | cut -d" " -f1)
secret/inlets-token created
- 創建一個 Service 對象
apiVersion: v1
kind: Service
metadata:
name: inlets
labels:
app: inlets
spec:
type: ClusterIP
ports:
- port: 8000
protocol: TCP
targetPort: 8000
selector:
app.kubernetes.io/name: inlets
- 創建一個 Deployment 對象
apiVersion: apps/v1
kind: Deployment
metadata:
name: inlets
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: inlets
template:
metadata:
labels:
app.kubernetes.io/name: inlets
spec:
containers:
- name: inlets
image: alexellis2/inlets:2.3.2
imagePullPolicy: Always
command: ["inlets"]
args:
- "server"
- "--token-from=/var/inlets/token"
volumeMounts:
- name: inlets-token-volume
mountPath: /var/inlets/
volumes:
- name: inlets-token-volume
secret:
secretName: inlets-token
然後可以創建一個 Ingress 對象或者使用 LoadBalancer 類型的 Service 來連接到上面的 inlets 服務:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: inlets
annotations:
kubernetes.io/tls-acme: "true"
spec:
tls:
- hosts:
- exit.qikqiak.com
secretName: exit-tls
rules:
- host: exit.qikqiak.com
http:
paths:
- path: '/'
backend:
serviceName: inlets
servicePort: 8000
我們這裡使用 cert-manager 來進行自動化的 HTTPS,當然如果你不需要對通信過程加密的話,直接使用 HTTP 即可。將上面的資源對象創建成功後,接下來我們就可以在我們本地安裝 inlets 客戶端:
# Install to /usr/local/bin/ (recommended)
curl -sLS https://get.inlets.dev | sudo sh
# Install to local directory
curl -sLS https://get.inlets.dev | sh
獲取上面我們創建的 Secret 對象的 Token:
$ kubectl get secret inlets-token -o jsonpath={.data.token} |base64 -d
856ef14d563221918c2d3b9c7d15af94ce9a6d63
然後在本地電腦上使用 inlets 客戶端打開隧道:
$ inlets client \\
--remote ws://exit.qikqiak.com \\
--upstream=exit.qikqiak.com=http://127.0.0.1:8000 \\
--token=856ef14d563221918c2d3b9c7d15af94ce9a6d63
2019/09/25 16:36:26 Upstream: exit.qikqiak.com => http://127.0.0.1:8000
2019/09/25 16:36:26 Token: "856ef14d563221918c2d3b9c7d15af94ce9a6d63"
Welcome to inlets.dev! Find out more at https://github.com/alexellis/inlets
map[X-Inlets-Id:[2d17ad31e4e1446bb99b2aecc0505f23] X-Inlets-Upstream:[exit.qikqiak.com=http://127.0.0.1:8000] Authorization:[Bearer 856ef14d563221918c2d3b9c7d15af94ce9a6d63]]
INFO[0000] Connecting to proxy url="wss://exit.qikqiak.com/tunnel"
- --token參數使我們的客戶端和出口節點進行身份驗證,可以防止未經授權的訪問。
- wss:// 可以讓我們使用加密隧道來防止攻擊,如果你不考慮安全問題,使用ws://即可。
到這裡,我們就可以在 Internet 上面通過訪問 https://exit.qikqiak.com 來訪問我本地電腦上運行在 8000 端口的服務了。
如果你本地有多個域名和多個服務需要代理,只需要更改--upstream參數即可,比如:
inlets client \\
--remote wss://exit.domain.com \\
--upstream=gateway.domain.com=http://127.0.0.1:8080,prometheus.domain.com=http://127.0.0.1:9090
我本地 8000 端口上面是一個簡單 Django 服務,所以現在在公網上面訪問 https://exit.qikqiak.com 即可訪問到本地服務資源:
inlets local server
這樣我們建立了一個完全免費的隧道,可以穿透幾乎所有防火牆。也解決了我們在 Internet 上面訪問我們內網服務的需求。到這裡,可能很多同學想到了將自己的 Raspberry Pi 利用起來了吧?
參考鏈接
- https://github.com/alexellis/inlets
- https://blog.alexellis.io/https-inlets-local-endpoints/
閱讀更多 k8s技術圈 的文章