使用frp實現內網穿透

diwugebingren發表於2019-04-05

現在辦理寬頻的時候,運營商都不會給你分配公網靜態ip,這導致的問題就是如果你想讓外部網路訪問家裡區域網內的某臺裝置,你不能使用一般路由器都自帶的埠對映(虛擬伺服器)來簡單的讓外部網路成功訪問到。在運營商動態分配ip的時候,如果動態分配到的ip是公網ip,那麼可以使用一些收費的DDNS動態域名解析服務來訪問內網中的web服務,這時候路由器的埠對映也是需要配置的。如果動態分配到的ip不是公網ip,那麼DDNS也不會靈光了。我們需要徹底一點的方案,那就是內網穿透,即通過一臺具有公網靜態ip的電腦(伺服器,vps等),來反向代理內網中的機器。

怎麼樣來理解通過反向代理穿透到內網呢,首先我們需要在具有公網靜態ip的服務端,安裝一個代理服務(例如本文將要提到的frp的服務端frps),然後在內網的裝置上安裝此代理服務的客戶端,服務端跟客戶端都作為後臺服務啟動執行(服務端首先啟動執行),客戶端連線到代理服務的埠,此時我們的服務端作為反向代理伺服器已經可以接受來自網際網路的請求了,並能夠把請求轉發到客戶端上設定好的相應埠(服務,例如web)上。簡而言之,現在我們可以從外部網路訪問內網中的某些設定好的裝置了。

前些日子,我想要在上班的時候也能訪問家裡的刷好openwrt的路由器的設定介面及ssh服務,所以通過google,最終我決定使用frp這個開源軟體,下面是github上的專案主頁:
github.com/fatedier/fr…
更多配置請訪問專案主頁自行研究。

折騰過程記錄:

前提:

  • 一臺有公網靜態ip的裝置(伺服器,vps,openwrt路由器...)。
  • 代理tcp協議不需要域名,代理http,https協議必須要準備域名。

服務端配置

首先從此處找到適合自己系統架構的編譯好的軟體包,點選右鍵,從彈出選單中找到複製連結地址單擊複製。

支援systemd的linux系統(ubuntu,centos7)

我使用的是centos7的vps,通過ssh登陸進去,使用wget命令列工具把軟體包下載到 /opt目錄下。

cd /opt
sudo wget 貼上複製的連結
複製程式碼

這時候將下載到的軟體包進行解壓。

ls
sudo tar xzvf  軟體包名
複製程式碼

解壓成功後進入剛剛解壓的檔案目錄。

ls
cd 剛解壓的目錄
ls
複製程式碼

可以看到frpc,frps,frpc_full.ini,frps_full.ini,frpc.ini,frps.ini等檔案,frps是服務端二進位制程式,frpc是客戶端二進位制程式,frps.ini是服務端的配置檔案,frpc.ini是客戶端的配置檔案,frps_full.ini跟frpc_full.ini是示例配置檔案。

使用frp實現內網穿透
在centos7下,可以通過systemd來管理守護程式,根據此github專案上issue上vc5寫的systemd 的service檔案修改了一份frps程式可用的service檔案,檔名改為frps.service,放在 /usr/lib/systemd/system/目錄下。

sudo cd /usr/lib/systemd/system
sudo vim frps.service
複製程式碼

輸入上一行命令後,進入空的frps.service檔案,點選i進入編輯模式,複製貼上下面的內容

[Unit]
Description=frps daemon
After=syslog.target  network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.ini
Restart= always
RestartSec=1min
ExecStop=/usr/bin/killall frps

[Install]
WantedBy=multi-user.target
複製程式碼

根據frps.service中啟動frps的那一行(ExecStart=......),將frps跟frps.ini移動或者複製到相應的目錄下。到這一步就可以把下載的軟體包跟解壓出來的資料夾刪除了。

cd /opt/frp資料夾名/
sudo cp frps /usr/local/bin#複製到該目錄下
sudo mkdir /etc/frp#新建資料夾frp
sudo cp frps.ini /etc/frp/#複製到該目錄下
sudo rm -rf 軟體包 解壓出來的資料夾
複製程式碼

現在來設定/etc/frp目錄下的frps.ini,通過cd /etc/frp切換到該目錄下,輸入vim frps.ini 命令修改frps.ini,我的配置如下:

#frps.ini
[common]
bind_port = 1978#可以自行設定

vhost_http_port = 8081#可以自行設定
vhost_https_port = 4433#可以自行設定

token=jsljgslaljglsgsgjlsjgslgjs#請自己設定金鑰
authentication_timeout=0#假如服務端與客戶端的時間相差超過24小時,可能會無法連線,此處設定為0,將不再驗證服務端與客戶端時間

log_file = ./frps.log
log_level = info
log_max_days = 3

subdomain_host = example.com#填寫自己的域名,此處填寫subdomain_host則代理http,https協議時客戶端在web代理中要填寫subdomain專案

複製程式碼

修改好frps.ini,服務端的配置基本完成,通過如下命令啟動執行:

sudo systemctl  enable frps.service#允許開機自啟
sudo systemctl  start frps.service#啟動
sudo systemctl  status frps.service#檢視執行狀態

複製程式碼

如果使用防火牆firewalld,frps相關服務埠可能並未開放,可以通過如下命令開放相關埠:

sudo firewall-cmd --permanent --add-port=相關服務埠/tcp #此處埠是配置檔案中設定好的埠,bind_port,vhost_http_port,vhost_https_port ,還有客戶端配置檔案中的遠端埠,請逐條新增
sudo firewall-cmd --reload

複製程式碼

客戶端配置

客戶端的配置前面幾步跟服務端類似,首先從此處找到適合自己系統架構的編譯好的軟體包並下載下來。

openwrt(LEDE)系統的路由器

把frpc複製到/usr/bin/目錄,把frpc.ini複製到/etc/目錄,根據網路上的教程,我嘗試了在web管理介面中新增到本地啟動指令碼中,輸入

nohup frpc -c /etc/frpc.ini > /dev/null 2>&1  &
複製程式碼

使用frp實現內網穿透
但這樣開機啟動的方式並不起作用。所以我用python編寫了一個監測frpc是否執行的指令碼,如果指令碼檢測到frpc沒有執行就會啟動frpc。將該指令碼命名為monitor.py,放在/root目錄下,內容是這樣的:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time

cmd="ps |grep frp |grep -v grep"
process=os.popen(cmd).readlines()
if process:
   time_now=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
   with open("monitor.log","at") as f:
        f.write(time_now+" running\n")
        for line in process:
            f.write(line)
else:
   time_now=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
   with open("monitor.log","at") as f:
        f.write(time_now+" no running\n")
   os.popen("frpc -c /etc/frpc.ini >/dev/null 2>&1 &")
複製程式碼

將monitor.py賦予執行許可權

chmod a+x monitor.py
複製程式碼

我們可以在linux的計劃任務cron中每十分鐘執行一次指令碼,我們在/etc/crontabs/root檔案的末尾新增上一條計劃任務

*/10 * * * * /root/monitor.py
複製程式碼

客戶端配置檔案frpc.ini:

[common]
server_addr = 0.0.0.0#填寫自己伺服器ip
server_port=1978 #可以自行設定
token=sgfsgsgshshshshshshshs #跟服務端必須一致

[ssh_router]#ssh連線
type = tcp
local_ip = 127.0.0.1
local_port = 22 #可以自行設定
remote_port=4555#可以自行設定

[web_router]#登入web
type=http#或者https
local_ip=127.0.0.1
local_port =80#可以自行設定
#此處無需設定遠端埠,服務端配置裡已經設定了vhost_http_port或vhost_https_port的埠
#如果服務端設定了subdomain_host,這裡設定subdomain,如果服務端沒有設定subdomain_host,這裡設定custom_domains
subdomain=router
#custom_domains = router.example.com

複製程式碼

當客戶端配置檔案修改好了,可以輸入 frpc -c /etc/frpc.ini測試能否連線服務端,如下圖所示說明配置正確連線成功了。

frp客戶端成功連線服務端
現在重啟openwrt路由器,過幾分鐘監測指令碼執行後就可以從外網登陸路由器web介面了。前面的內容也適用於沒有使用systemd的其他linux系統。

支援systemd的linux系統(ubuntu,centos7)

客戶端配置跟服務端幾乎一樣,只需要注意兩點,第一點就是編寫service檔案時把 frps替換成frpc,第二點就是使用客戶端的配置檔案frpc.ini。

歡迎瀏覽我的個人部落格,https://diwugebingren.github.io

歡迎關注我的公眾號

相關文章