WordPress Multisite Domain 映射 SNI 的 SSL for NGINX - MIS 腳印
MIS 腳印 logo

MIS 腳印

記錄 IT 學習的軌跡

WordPress Multisite Domain 映射 SNI 的 SSL for NGINX

想自行建立類似 WordPress.com 的網路平台服務嗎?透過 WordPress.org Multisite (多站點) Domain (網域名稱) 映射,就可使用同一個 IP 新增多個不同 Domain 的子站點網站,再搭配 NGINX 的 SNI 功能,即可讓同一個 IP 提供多個 HTTPS 的網站。

WordPress.ORG

WordPress Multisite (多站點) 可以映射不同的 Domain Name (網域名稱,簡稱 Domain),這表示可以將主站點 (如 footmark.info) 映射到不同網域名稱 (如 greenart.com.tw),但須要一些額外的設定。

WordPress Multisite Domain 映射

WordPress 4.5 版本之前,與主站點不同 Domain 的映射必須使用外掛 (例如 WordPress MU Domain Mapping) 才能實現。

WordPress 4.5+ 版本以上,預設已支援不同 Domain 的映射功能。

站點配置

本文章會建立 1 個主站點及 3 個子站點,配置內容如下表:

WordPress 多站點配置
主站點 子站點 子域名 與主站點不同 Domain
footmark.info test.footmark.info  
greenart.com.tw  
test.greenart.com.tw

啟用 WordPress Multisite

請參考建置 WordPress MU 多子網域 HTTPS for CentOS 7 + NGINX + PHP 7,來啟用 WordPress Multisite 的功能 。

DNS 設定

至購買網域名稱所提供的 DNS (Domain Name System,網域名稱系統) 代管服務設定 DNS,本文章將以 GoDaddy 為例。將與主站點不同 Domain 的 DNS A 和 CNAME 類型,設定與主站點相同即可 (本文章為 greenart.com.tw),主要是 A 類型 IP 必須跟主站點一樣。

footmark.info DNS 設定:

greenart.com.tw DNS 設定:

安裝 SSL 萬用憑證

所有與主站點不同的 Domain,都必須要各別安裝 SSL,本文章為 greenart.com.tw。

請參考 acme.sh 搭配 GoDaddy 自動續期 Let’s Encrypt 免費萬用憑證,來安裝 Domain greenart.com.tw 免費的 SSL 萬用憑證。

NGINX 設定

確定您的 NGINX 是否支援在相同一個 IP 能提供多個 HTTPS 網站的 SNI (Server Name Indication,伺服器名稱指示) 功能 (參考 Server Name Indication):

nginx -V
nginx version: nginx/1.14.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
# 確定有支援並啟用
TLS SNI support enabled

# ... 以下省略 ...

配置 NGINX 設定檔,重覆主站點兩個 server 區塊的設定,並將所有 footmark.info 替換成 greenart.com.tw 即可:

vim /etc/nginx/conf.d/default.conf
map $http_host $blogid {
    default       -999;

    #Ref: http://wordpress.org/extend/plugins/nginx-helper/
    #include /var/www/wordpress/wp-content/plugins/nginx-helper/map.conf;
}

server {
    listen 80;
    listen [::]:80;
    server_name footmark.info *.footmark.info;
    return 301 https://$server_name$request_uri;
}

server {
    # 使用 https 和 http/2 協定
    listen 443 ssl http2;
    # 上述的 IPv6 方式
    listen [::]:443 ssl http2;

    server_name footmark.info *.footmark.info;

    #
    # 上傳檔案相關設定
    #

    # 上傳檔案允許容量
    client_max_body_size 200M;

    client_header_timeout 600s;
    client_body_timeout 600s;

    # fastcgi 為使用本機的 php-fpm,如果是透過 proxy 則前綴要改成 proxy_
    fastcgi_connect_timeout 600s;
    fastcgi_read_timeout 600s;
    fastcgi_send_timeout 600s;


    # 瀏覽器 Cache 期限 (1M = 1 Month)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff)$ {
        expires 1M;
    }
        

    root /usr/share/nginx/html;
    index index.php;


    #
    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    #

    # SSL 憑證證書路徑
    ssl_certificate /etc/nginx/ssl/footmark.info/cert.pem;
    # 私鑰路徑
    ssl_certificate_key /etc/nginx/ssl/footmark.info/key.pem;
    # 緩存有效期
    ssl_session_timeout 1d;
    # 緩存憑證類型和大小
    ssl_session_cache shared:SSL:50m;


    #
    # intermediate configuration. tweak to your needs.
    #

    # 使用的加密協定
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # 加密演算法,越前面的優先級越高
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    # 交握過程使用 Server 的首選加演算法,這裡使用 Client 為首選
    ssl_prefer_server_ciphers on;


    #
    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    #

    # 增加 http header
    add_header Strict-Transport-Security max-age=15768000;


    location / {
        try_files $uri $uri/ /index.php?$args ;
    }

    location ~ \.php$ {
        try_files $uri = 404;
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    #WPMU Files
    location ~ ^/files/(.*)$ {
        try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1;
        access_log off;
        log_not_found off;
        expires max;
    }

    #WPMU x-sendfile to avoid php readfile()
    location ^~ /blogs.dir {
        internal;
        alias /usr/share/nginx/html/wp-content/blogs.dir;
        access_log off;
        log_not_found off;
        expires max;
    }

    #add some rules for static content expiry-headers here
}

server {
    listen 80;
    listen [::]:80;
    server_name greenart.com.tw *.greenart.com.tw;
    return 301 https://$server_name$request_uri;
}

server {
     # 使用 https 和 http/2 協定
     listen 443 ssl http2;
     # 上述的 IPv6 方式
     listen [::]:443 ssl http2;
 
     server_name greenart.com.tw *.greenart.com.tw;
 
     # ... 省略 (同上) ...

     #
     # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
     #
 
     # SSL 憑證證書路徑
     ssl_certificate /etc/nginx/ssl/greenart.com.tw/cert.pem;
     # 私鑰路徑
     ssl_certificate_key /etc/nginx/ssl/greenart.com.tw/key.pem;
 
     # ... 省略 (同上) ...
 }

重啟 NGINX 和 PHP-FPM 服務:

systemctl restart nginx php-fpm

新增 WordPress 子站點

與主站點相同 Domain

新增子站點 test.footmark.info:

訪問首頁:

與主站點不同 Domain

新增子站點 greenart.com.tw 時,會發現「網站位址」後的 Domain 是無法修改的,這裡先隨便新增一個不重覆的「網站位址」即可:

「新增網站」後點擊編輯:

將「網站位址」修改成您要映設的 Doman 完整網址 (這裡為 https://greenart.com.tw/):

訪問首頁:

WordPress 設定

登入與主站點不同 Domain 的子站點時,會出現 Cookies 被阻擋的錯誤:

必須於 WordPress 的設定檔 wp-config.php 加入這個設定 (參考 WordPress Multisite Domain Mapping | WordPress.org):

vim /usr/share/nginx/html/wp-config.php
<?
# ... 以上省略 ...

define('COOKIE_DOMAIN', $_SERVER['HTTP_HOST']);

參考

發表迴響