<menu id="ycqsw"></menu><nav id="ycqsw"><code id="ycqsw"></code></nav>
<dd id="ycqsw"><menu id="ycqsw"></menu></dd>
  • <nav id="ycqsw"></nav>
    <menu id="ycqsw"><strong id="ycqsw"></strong></menu>
    <xmp id="ycqsw"><nav id="ycqsw"></nav>
  • ddns動態域名解析系統(路由器動態域名解析)


    接著上篇 《使用 Nginx 提供 DDNS 服務(前篇)》繼續聊聊如何玩轉 Nginx 和 NJS,本篇將基于上一篇的內容,調整架構,讓這套服務能夠在云端運行,降低本地調用成本。

    本篇文章中,我們實際使用的代碼行數會比上篇文章更少,全部代碼 150 行左右。

    寫在前面

    和上篇文章一樣,我們需要先了解本篇內容中的服務架構和工作流程,為了便于理解,我畫了一個簡單的流程圖。

    使用 Nginx 提供 DDNS 服務(中篇)

    如果你是 NAS 或者向日葵這類軟件服務用戶,你會發現圖中的模式和你之前使用的模式幾乎一模一樣。

    在這個方案中,我們本地不再需要運行容器或者 Nginx 實例,在路由器或者 NAS 中運行一個計劃任務,使用 Curl 之類的方式定時調用在云服務器上部署的服務接口,即可完成 DDNS 記錄更新,甚至你在家用電腦上打開網站,設置頁面自動刷新也可以達到同樣的效果。

    相比較方案一,這個方案對于設備要求更低一些,至于使用哪一種,根據自己手里設備資源狀況來確定就好啦。

    那么,我們就來展開聊聊,怎么通過 Nginx 和容器完成這個服務方案。

    使用 Nginx 完成 IP 獲取邏輯

    我們還是使用 Nginx 先來完成 IP 獲取邏輯,這里我們有兩個選擇,一個是和前文一樣,使用外部服務來完成 IP 查詢邏輯,還有一個選擇便是直接使用 Nginx 來高效的完成這個功能。

    因為部署在云端,獲取 IP 和 DNS 記錄更新邏輯可以合并在一起,但是為了方便理解,這里將兩部分拆解開來進行描述。

    常規和一般容器方案

    如果你在云服務器上通過 APT 或 YUM 安裝 Nginx ,那么直接使用下面的配置啟動 Nginx ,就能夠將訪問者的 IP 展示出來啦。

    server {
        listen 80;
        server_name localhost;
        charset utf-8;
    
        location / {
            default_type text/plain;
            return 200 "$remote_addr";
        }
    }

    當然,為了維護更簡單,推薦使用容器來啟動服務,將上面的配置保存為 nginx.conf ,然后編寫編排文件:

    version: "3"
    services:
    
      ngx-whats-myip:
        image: nginx:1.21.1-alpine
        volumes:
          - ./nginx.conf:/etc/nginx/templates/default.conf.template:ro
        ports:
          - 80:80
        environment:
          - NGINX_ENTRYPOINT_QUIET_LOGS=1

    然后,將上面的內容保存為 docker-compose.yml ,使用 docker-compose up -d 啟動服務,訪問服務器 IP 和你指定的端口,一個屬于你自己的私有的查詢 IP 的服務就就緒啦。

    如果你是我的老讀者,我更推薦你使用 Traefik 進行維護管理。

    Traefik 方案

    使用 Traefik 可以讓你更輕松的管理服務域名,進行動態快速的服務發現,但是因為要經過 Traefik 這個網關,所以我們需要進行一些配置調整,才能夠讓服務正常運行。

    先對 Nginx 配置文件進行調整:

    server {
        listen 80;
        server_name localhost;
        charset utf-8;
    
        set_real_ip_from 172.160.0.0/16;
        set_real_ip_from 172.170.0.0/16;
        set_real_ip_from 172.180.0.0/16;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
    
        location / {
            default_type text/plain;
            return 200 "$remote_addr";
        }
    }

    可以看到我這里使用 set_real_ip_from 設置了三個信任的網絡環境,這些數值是怎么來的呢?很簡單,使用 docker info ,可以看到輸出信息最下面有類似這樣的信息:

    ...
    ...
     Live Restore Enabled: false
     Default Address Pools:
       Base: 172.160.0.0/16, Size: 24
       Base: 172.170.0.0/16, Size: 24
       Base: 172.180.0.0/16, Size: 24

    這里你有幾個地址,就將幾個地址填充到配置里即可。此外,容器編排文件中添加 Traefik 聲明即可:

    version: "3"
    services:
    
      ngx-ip:
        image: nginx:1.21.1-alpine
        volumes:
          - ./nginx.conf:/etc/nginx/templates/default.conf.template:ro
        networks:
          - traefik
        labels:
          - "traefik.enable=true"
          - "traefik.docker.network=traefik"
    
          - "traefik.http.routers.ngx-whatsmyip-www.entrypoints=http"
          - "traefik.http.routers.ngx-whatsmyip-www.rule=Host(`whatsmyip.lab.io`)"
          - "traefik.http.routers.ngx-whatsmyip-ssl.entrypoints=https"
          - "traefik.http.routers.ngx-whatsmyip-ssl.tls=true"
          - "traefik.http.routers.ngx-whatsmyip-ssl.rule=Host(`whatsmyip.lab.io`)"
    
          - "traefik.http.services.ngx-whatsmyip-backend.loadbalancer.server.scheme=http"
          - "traefik.http.services.ngx-whatsmyip-backend.loadbalancer.server.port=80"
    
    networks:
      traefik:
        external: true

    關于 Traefik 的使用,可以參考之前的文章,如果你沒有使用過服務發現,那么它會打開你新世界的大門。

    當然,如果你還是希望使用外部服務,也可以繼續使用公網 IP 查詢服務。關于公網 IP 查詢服務,文章末尾有聊,感興趣的朋友可以自取。

    調整 DNS 注冊服務

    在上一篇文章中,我們有提到可以使用健康檢查來完成類似計劃任務的功能來進行周期性的 DNS 記錄更新。在這個場景下,我們需要進行一些調整。

    先來調整 NJS 邏輯,相比較之前需要實現一個 whatsMyIP 來獲取外部 IP 地址,這次我們可以通過 r.remoteAddress 屬性字段簡單的獲取 IP。

    function main(r) {
        const clientIP = r.remoteAddress;
        const domain = recordName;
        getRecordIds(r, zoneId, domain).then(recordId => {
    
            if (recordId) {
                updateExistRecord(r, zoneId, domain, recordId, clientIP).then(response => {
                    r.return(200, response);
                }).catch(e => r.return(500, e));
    
            } else {
                createRecordByName(r, zoneId, domain, clientIP).then(response => {
                    r.return(200, response);
                }).catch(e => r.return(500, e));
            }
    
        }).catch(e => r.return(500, e));
    }
    
    
    export default { main }

    Nginx 參考前文,也可以進行一些簡單的調整。

    load_module modules/ngx_http_js_module.so;
    
    user nginx;
    worker_processes auto;
    
    error_log /var/log/nginx/error.log notice;
    pid /var/run/nginx.pid;
    
    
    events {
        worker_connections 1024;
    }
    
    http {
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
    
        log_format main '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log /var/log/nginx/access.log main;
    
        keepalive_timeout 65;
        gzip on;
    
        js_path "/etc/nginx/njs/";
        js_import app from app.js;
    
        server {
            listen 80;
            server_name localhost;
    
            charset utf-8;
            gzip on;
            set_real_ip_from 172.160.0.0/16;
            set_real_ip_from 172.170.0.0/16;
            set_real_ip_from 172.180.0.0/16;
            real_ip_header X-Forwarded-For;
            real_ip_recursive on;
    
            # Bind request to CF
            location /client/v4/ {
                internal;
                gunzip on;
                proxy_set_header "X-Auth-Email" "${DNS_CF_USER}";
                proxy_set_header "X-Auth-Key"   "${DNS_CF_TOKEN}";
                proxy_set_header "Content-Type" "application/json";
                proxy_pass "https://api.cloudflare.com/client/v4/";
            }
    
            location / {
                default_type text/plain;
                js_content app.main;
            }
    
        }
    }

    可以看到,因為私有化部署,這次服務的代碼實現要比之前更精簡一些。

    因為調用方式發生改變,前文中我們使用健康檢查定期調用注冊更新接口的方式不能使用了,所以我們要單獨創建一個接口地址,讓容器進行調用,確保服務穩定。

    ...
    
        location = /health {
            default_type text/plain;
            access_log off;
            return 200 'alive';
        }
    
    ...

    當然,編排文件中對應的檢查地址也需要進行更新:

    ...
    healthcheck:
      test: ["CMD", "curl", "--silent", "--fail", "http://localhost/health"]
      interval: 5s
      timeout: 5s
      retries: 3
    ...

    使用 Traefik 針對服務進行頻率限制

    因為不同服務商的接口都存在一定的調用限制,除了像之前文章一樣,在調用的時候進行頻率限制外,還可以在服務接口處進行調用頻率限制,比如下面的配置就限制每個來源每分鐘限制調用 10 次。

    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik"
    
      - "traefik.http.middlewares.test-ratelimit.ratelimit.average=10"
      - "traefik.http.middlewares.test-ratelimit.ratelimit.burst=1"
      - "traefik.http.middlewares.test-ratelimit.ratelimit.period=1m"

    如果你希望添加鑒權,進一步減少公開調用,可以參考之前的文章 《Traefik 2 基礎授權驗證(前篇)》 進行配置。

    補充公網 IP 查詢服務

    公網上能夠做到 IP 查詢的服務很多,上篇文章中,我們使用的是自 2010 年運行至今的 SOHU 打點接口,穩定性還是比較有保障的。如果你希望使用更中立的服務商,可以考慮 IPIP 的服務。

    在上篇文章發布后,國內專業的 IP 地址庫產品 IPIP 的創始人,高春輝大叔留言提醒 IPIP 也有免費的 IP 自查服務。

    使用方法也很簡單,只需要參考下面的配置,更新之前的配置即可:

    server {
        listen 80;
        server_name localhost;
    
        # Bind request to ipip.net
        location /proxy/myip {
            proxy_pass "http://myip.ipip.net/s";
        }
    }

    說起這個服務,還有一個小細節,不論是使用 Nginx 反向代理的是 HTTP 協議還是 HTTPS 協議,在不配置 gunzip 的情況下,你會發現都可以正常訪問。這里或許是作者的小細節,為了照顧新手以及方便調用者,在使用 CDN 保護接口的同時,特別關閉掉了數據壓縮。我做了一個小測試,針對 IP 類返回結果,開啟壓縮至少可以節約 30~40% 的流量。

    版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。

    發表評論

    登錄后才能評論
    国产精品区一区二区免费