新手自建 Docker 伺服器 - (2) 建立 Nginx 代理伺服器

建立反向代理,設定 domain 到對應的 docker 服務器

這一系列文章,是我自己完成 Docker Server 建立的經歷以及過程,包含以下章節內容:

  1. 新手自建 Docker 伺服器 - (0) 簡介與架構說明
  2. 新手自建 Docker 伺服器 - (1) Ubuntu 主機建立 docker 服務
  3. 新手自建 Docker 伺服器 - (2) 建立 Nginx 代理伺服器
  4. 新手自建 Docker 伺服器 - (3) 建立應用,以靜態網頁為例
  5. 新手自建 Docker 伺服器 - (4) 建立 Joplin 筆記軟體
  6. 新手自建 Docker 伺服器 - (5) 建立自己的音樂串流服務 Navidrome

自建 Docker 伺服器 - (2) 建立 Nginx 代理伺服器

這篇算是開始進入最重要的部分,在我們把 infra 環境建立起來後,而在建立服務之前,我們必須要搭建反向代理,讓每個 request 進來時,由 nginx 來判斷要去到哪一個 docker 服務,而將服務內容返回給使用者。

因此我們再來看一次系統架構圖,這張圖我是用 Plantuml 畫出來的,這次我們的幾個重點如下:

  
@startuml
left to right direction
skinparam actorStyle awesome
rectangle "Ubuntu" as ub {
  package Docker {
    usecase "Nginx" as ng
    note top of ng
      listen XXX
      Reverse to XXX.domain docker
    end note
    usecase "DockerA" as dka
    usecase "DockerB" as dkb
  }
}
note left of ub
  Create on Linode
  IP: 1.1.1.1
end note
"User" as u
u --> (Cloudflare) : XXX.domain
note top of (Cloudflare)
  A Record: XXX.domain -> 1.1.1.1
end note
(Cloudflare) --> ng
ng --> dka : AAA.domain
ng --> dkb : BBB.domain
@enduml

  
  1. 使用者從 clent 端都是打 xxx.domain 進入服務器,而在 Cloudflare 上都是設定我們這台 ubuntu IP(1.1.1.1)。
  2. 因此使用者其實都是透過 1.1.1.1:443 或 1.1.1.1:80 訪問我的 Nginx。
  3. Nginx 透過反向代理的方式來判斷要去到哪一個 docker 服務,這會在每一個 docker compose 內定義。

步驟一:建立 docker 網路

最重要卻也最簡單的一步,我們要優先建立 docker 內部使用的網路,來確保後續我們的 docker 服務是可以互相通訊的

sudo docker network create net #建立一個名為'net'的網路

步驟二:建立 docker 資料夾與 nginx 資料夾

在主機建立一個 Nginx 的資料夾,接著進去後建立存放資料的資料夾(也可以不設定…但我就習慣想要資料放本機而不是在 docker 裡面)

mkdir nginx-proxy && cd nginx-proxy #建立 docker 專案資料夾
mkdir nginx-data && cd nginx-data #nginx 存放資料的位置
mkdir {conf.d,html,dhparam,vhost,certs} #建立要保存的幾個資料夾
cd .. #回到nginx-proxy資料夾
chmod -R 777 nginx-data #給 nginx-data 權限

步驟三:撰寫 docker compose

在 nginx-proxy 資料夾,透過指令建立 docker compose 檔案

nano docker-compose.yml

貼上以下 docker compose 內容,這裡的幾個部分可以稍微理解下

  1. 除了 nginx-proxy,還另外安裝了一個 letsencrypt 服務來自動申請 SSL 憑證,這樣假如要做多個不同 domain 服務時也可以使用
  2. 掛載的資料夾要對應上一部生成的資料夾位置
  3. network 要對應第一步驟建立的 docker 網路名稱
  4. Email 填入自己的
version: '3.7'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx-data/conf.d:/etc/nginx/conf.d
      - ./nginx-data/html:/usr/share/nginx/html
      - ./nginx-data/dhparam:/etc/nginx/dhparam
      - ./nginx-data/vhost:/etc/nginx/vhost.d
      - ./nginx-data/certs:/etc/nginx/certs
      - /var/run/docker.sock:/tmp/docker.sock:ro
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
    restart: always
    networks:
      - net

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: lets-encrypt-proxy-companion
    depends_on:
      - "nginx-proxy"
    volumes:
      - ./nginx-data/certs:/etc/nginx/certs
      - ./nginx-data/vhost:/etc/nginx/vhost.d
      - ./nginx-data/html:/usr/share/nginx/html
      - ./var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      DEFAULT_EMAIL: YOUR_EMAIL
    restart: always
    networks:
      - net

networks:
  net:
    external: true

步驟四:部署,檢查 nginx 是否生效

完成 docker compose 後,接著透過指令部署

docker compose up -d

部署之後,可以在 broswer 打開 http://1.1.1.1 來檢查 nginx 是否正常運作,另外這邊記得要把防火牆的 80 與 443 開啟,理論上看到 Nginx 503,就代表成功啦

完成了!代表什麼意思

到這一步,我們已經順利的把所有底層 docker 環境、以及代理伺服器建立起來,等於是我們已經 建立好一條從外部連進Server 的通道 ,因此接下來我們就能夠專注在 Server 上部署各種 Docker 應用程式了。

而之後要注意的是,如果你的 docker 要對外連線的話,在 docker compose 內的 environment 中的變數要加上 VIRTUAL_HOST ,如果要 SSL 憑證則要再加上 LETSENCRYPT_HOST

environment:
    - VIRTUAL_HOST=domain.com  #你自己擁有或要管理的 domain
    - LETSENCRYPT_HOST=domain.com #可以自己決定要不要使用,有的話可以 https 連線

如果你有碰到什麼困難,歡迎寫 email 給我來討論喔

comments powered by Disqus