使用 SSH tunnel, NGINX reverse proxy 自製 ngrok 服務

    如果在家中或在任何內網中佈建了一些服務,需要從外部連入,Reverse SSH tunnel (Remote Port Forwarding),是一個很好的選擇。但是如果要讓在 Internet 上的人可以存取這個內部的服務,就必須要有外部網站再轉 tunnel 的服務,這也就是 ngrok 所提供的服務之一。ngrok 雖然有提供免費的服務,但是限制頗多。如果並不常用,訂閱起來也蠻浪費的。

    如下圖,本文要說明的是如何實作自製的 ngrok 服務,其中會使用下面幾種技術:

    • Reverse SSH tunnel (Remote Port Forwarding)
    • NGINX reverse proxy
    • (optional) Let’s Encrypt

    要做到本文的成果,您必須要有:

    • domain name
    • Internet 上的 Linux server (自建或 Cloud 服務),以下使用 GCP
    在 Mac 中設定開機自動連接 SSH tunnel

    參考此篇:https://blog.kylemanna.com/osx/ssh-reverse-tunnel-on-mac-os-x/

    建立持續連接的 SSH reverse tunnel

    在內部機器使用以下指令,連接建立 SSH tunnel,將內部實際提供服的 port 3000,連接到外部 GCP VM 的 port 13000,並使其持續連接,不會因為閒置沒有流量而斷掉:

    ssh -o TCPKeepAlive=yes -o ServerAliveCountMax=20 -o ServerAliveInterval=15 -NR 13000:localhost:3000 [email protected]
    參數說明:
    
    -o: 覆蓋 ssh_config 的選項
    -f: 背景執行
    -N: 不執行遠端指令,適用於 port forwarding (reverse tunnel)
    -R: 執行 remote port forwarding (reverse tunnel)
    
    13000: 遠端 server 的 port
    localhost: 本機
    3000: 本機的 port
    
    TCPKeepAlive: 持續送出 KeepAlive 封包,以保持連線
    ServerAliveInterval: 每送出一次 KeepAlive,會等幾秒回應
    ServerAliveCountMax: 最多等幾次沒有回應的 KeepAlive,以上面指令為例,如果 20x15=300 秒,沒有收到回應,才會斷開。
    
    /

    安裝 NGINX

    sudo apt update
    sudo apt upgrade
    sudo apt install nginx

    設定 NGINX: 設定 Virtual Host、使用 Reverse Proxy

    先完成支援 HTTP 的設定

    hlchang@ubuntu-1:~$ cd /etc/nginx/sites-available/
    hlchang@ubuntu-1:~$ sudo vi tunnel
    server {
      server_name tunnel.example.com; # Virtual Host 的名稱
      listen 443 ssl;
      location /gf/ {  # 將 /gf 導引到建立好的 SSH tunnel
          proxy_pass http://localhost:13000/;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto https;
          proxy_redirect off;
      }
    
      location /lgtn/ {
          proxy_pass http://localhost:18086/;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto https;
          proxy_redirect off;
      }
    }

    連結至 sites-enabled 目錄、重新啟動 NGINX

    hlchang@ngrok:~$ cd ../sites-enabled
    hlchang@ngrok:~$ sudo ln -s ../sites-available/tunnel .
    hlchang@ngrok:~$ sudo service nginx restart

    安裝支援 NGINX 的 Let’s Encrypt Certbot

    hlchang@ngrok:~$ sudo apt install certbot python3-certbot-nginx

    使用 Certbot 申請與驗證憑證,並自動更新 NGINX 設定檔

    注意:使用時,必須確保 HTTP 在 Port 80 有提供服務,否則無法完成驗證。

    hlchang@ngrok:~$ sudo certbot --nginx -d tunnel.example.com
    Saving debug log to /var/log/letsencrypt/letsencrypt.log
    Plugins selected: Authenticator nginx, Installer nginx
    Enter email address (used for urgent renewal and security notices) (Enter 'c' to
    cancel): [email protected]
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Please read the Terms of Service at
    https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
    agree in order to register with the ACME server at
    https://acme-v02.api.letsencrypt.org/directory
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    (A)gree/(C)ancel: A
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Would you be willing to share your email address with the Electronic Frontier
    Foundation, a founding partner of the Let's Encrypt project and the non-profit
    organization that develops Certbot? We'd like to send you email about our work
    encrypting the web, EFF news, campaigns, and ways to support digital freedom.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    (Y)es/(N)o: N
    Obtaining a new certificate
    Performing the following challenges:
    http-01 challenge for tunnel.example.com
    Waiting for verification...
    Cleaning up challenges
    Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/tunnel
    
    Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    1: No redirect - Make no further changes to the webserver configuration.
    2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
    new sites, or if you're confident your site works on HTTPS. You can undo this
    change by editing your web server's configuration.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
    No matching insecure server blocks listening on port 80 found.
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Congratulations! You have successfully enabled https://tunnel.example.com
    
    You should test your configuration at:
    https://www.ssllabs.com/ssltest/analyze.html?d=tunnel.example.com
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
    IMPORTANT NOTES:
     - Congratulations! Your certificate and chain have been saved at:
       /etc/letsencrypt/live/tunnel.example.com/fullchain.pem
       Your key file has been saved at:
       /etc/letsencrypt/live/tunnel.example.com/privkey.pem
       Your cert will expire on 2020-11-29. To obtain a new or tweaked
       version of this certificate in the future, simply run certbot again
       with the "certonly" option. To non-interactively renew *all* of
       your certificates, run "certbot renew"
     - Your account credentials have been saved in your Certbot
       configuration directory at /etc/letsencrypt. You should make a
       secure backup of this folder now. This configuration directory will
       also contain certificates and private keys obtained by Certbot so
       making regular backups of this folder is ideal.
     - If you like Certbot, please consider supporting our work by:
    
       Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
       Donating to EFF:                    https://eff.org/donate-le

    確認最後的 NGIX Virtual Host 設定檔

    hlchang@ubuntu-1:~$ cd /etc/nginx/sites-available/
    hlchang@ubuntu-1:/etc/nginx/sites-available$ more tunnel
    server {
      server_name tunnel.example.com;
      listen 443 ssl;
      location /gf/ {
          proxy_pass http://localhost:13000/;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto https;
          proxy_redirect off;
      }
    
      location /lgtn/ {
          proxy_pass http://localhost:18086/;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto https;
          proxy_redirect off;
      }
    
        #listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/tunnel.example.com/fullchain.pem; # ma
    naged by Certbot
        ssl_certificate_key /etc/letsencrypt/live/tunnel.example.com/privkey.pem; #
    managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    }

    發佈留言

    發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

    這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料