How to Create Local Https Server & Local Custom Domain on MacOS with Node.js
為什麼會有這篇文章
身為前端工程師,網頁正在開發或測試時,偶爾會有一些需求(常見的情況是整合第三方服務的時候),某個功能或是串接的服務只能在https的環境或是指定的網域下才能正常使用
導致開發時,沒辦法在local就確定服務是否有串接成功,可能必須要上alpha, beta甚至production
不只有你,我也遇到了哈哈哈
所以花一些時間整理成這篇文章
記錄一下讓自己以後能夠無腦按照文章做
誰適合這篇文章
如果你用MacOS & Node.js、不熟悉openssl,平常只會起local開發用的http web server,找了很多文章弄ssl都失敗
想要無腦的讓http前面加上s,甚至還有客製化網域
那這篇文章很適合你
這篇文章,沒有任何技術說明,全是過程
我不會跟你講什麼是openssl、什麼是Root CA
技術細節大家可以自己去Google或是看看最下面的Reference
過程中只會講解主要的流程,不會講技術細節
目標就是大家照著做,就可以有lcoal https server & custom doamin
Let’s Go!
Prepare
安裝Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
安裝openssl
brew install openssl
建立專案&對應的資料夾
project
├── server
│ ├── ssl
│ ├── index.js // entry of node.js server
Step 1. 新增openssl config
在ssl資料夾底下新增openssl.cnf
檔案,直接複製貼上下面的內容
然後改一下O
、OU
、emailAddress
組織名稱跟部門名稱還有email都可以自己隨便寫,不存在也沒關係
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=TW # 國別
ST=Taiwan # 國名
L=Taipei # 城市
O=CryptoInform # 組織名稱
OU=Dev # 組織底下的部門名稱
emailAddress=dev@cryptoinform.app # 聯絡用email
CN = localhost
新增完之後,資料夾結構會變這樣子:
project
├── server
│ ├── ssl
│ │ ├── openssl.cnf
│ ├── index.js // entry of node.js server
Step 2. 建立 self-signed root certificate
在ssl資料夾底下,執行下面2個指令
openssl req -x509 -nodes -new -sha256 -days 390 -newkey rsa:2048 -keyout "RootCA.key" -out "RootCA.pem" -config openssl.cnf
openssl x509 -outform pem -in "RootCA.pem" -out "RootCA.crt"
其中可以看到,第一行有一個參數是 -days 390
,意義是390天之後會過期,因為2020/09/01之後,產生的SSL/TLS certificates的有效期限最多是397天(13個月),超過就會出現Error,所以如果要自己改,記得數字不要超過397
Detail Here: https://stackoverflow.com/a/65239775.
執行結果:
執行指令完之後,資料夾結構會變這樣子:
project
├── server
│ ├── ssl
│ │ ├── openssl.cnf
│ │ ├── RootCA.crt
│ │ ├── RootCA.key
│ │ ├── RootCA.pem
│ │ ├── RootCA.srl
│ ├── index.js // entry of node.js server
Step 3: 定義certificate支援的domains/subdomains
在ssl資料夾底下,新增一個vhosts_domains.ext
檔案,然後複製貼上下面的內容
然後改一下DNS.1
、DNS.2
,有需要的話也可以新增DNS.3
、DNS.4
…,改成你希望支援https的domain
以下圖為例的話,這個certificate支援下面的網域
dev.cryptoinform.app
localhost
也就是說你可以透過https在local訪問這些網域!
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1=dev.cryptoinform.app # 1st domain with https
DNS.2=localhost # 2nd domain with https
執行完之後,資料夾結構會變這樣子:
project
├── server
│ ├── ssl
│ │ ├── openssl.cnf
│ │ ├── RootCA.crt
│ │ ├── RootCA.key
│ │ ├── RootCA.pem
│ │ ├── RootCA.srl
│ │ ├── vhosts_domains.ext
│ ├── index.js // entry of node.js server
Step 3. 新增certificate
一樣,在ssl資料夾底下,接著執行下面2個指令
openssl req -new -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.csr -config openssl.cnf
openssl x509 -req -sha256 -days 1024 -in localhost.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -extfile vhosts_domains.ext -out localhost.crt
執行結果:
新增完之後,資料夾結構會變這樣子:
project
├── server
│ ├── ssl
│ │ ├── localhost.crt
│ │ ├── localhost.csr
│ │ ├── localhost.key
│ │ ├── openssl.cnf
│ │ ├── RootCA.crt
│ │ ├── RootCA.key
│ │ ├── RootCA.pem
│ │ ├── RootCA.srl
│ │ ├── vhosts_domains.ext
│ ├── index.js // entry of node.js server
Step 4. 在Node.js Server中載入certificate
這是index.js
的內容
主要就是在啟動Node.js Server時載入certificate,並且把req/res轉送給Next.js處理
const https = require('https');
const next = require('next');
const fs = require('fs');
const PORT = 443
const app = next({ dev: process.env.NODE_ENV !== 'production' });
const handle = app.getRequestHandler();
const httpsOptions = {
key: fs.readFileSync('./ssl/localhost.key'),
cert: fs.readFileSync('./ssl/localhost.crt'),
};
app.prepare().then(() => {
https
.createServer(httpsOptions, (req, res) => {
handle(req, res);
})
.listen(PORT);
console.log(`> Server started on https://localhost:${PORT}`);
});
執行Server之後,你如果訪問https://localhost
,你會發現你的頁面會顯示「你的連線不是私人連線」
雖然點擊「進階」再選擇「繼續前往localhost網站(不安全)」是可以成功存取網站頁面的
不過就會像下圖這樣,https前面多了一個「不安全」的說明文字
Step 5: 在MacOS中載入certificates
會有https前面多了一個「不安全」的說明文字,主要是因為MacOS還不知道這些憑證是不是可以信任的,所以我們這邊打開ssl資料夾,在下面2個檔案各點擊2下,打開certificates
打開之後會分別看到2個「加入憑證的視窗」,都直接按加入就可以
都加入完成之後,打開MacOS內建的「鑰匙圈存取」App
在左邊側欄中選擇「登入」、「憑證」,就可以在右邊列表中看到2個名為localhost
的項目,圖示上一個是橘色,一個是藍色
接著像下圖雙擊點開這2個檔案
接著將「使用此憑證時」改為「永遠信任」
然後直接關閉,系統會要求你輸入密碼確認要更改,接著回「鑰匙圈存取」App,可以看到圖示右下角多了一個「+」的符號
到這邊憑證的設定就基本上完成了,可以在瀏覽器中開啟https://localhost
確認一下,設定正確的話就會像是下圖一樣,localhost
網域前面不會出現「不安全」的說明文字
Step 6: 設定custom domains
我們開啟Finder,按照下圖,選擇「前往」、「前往檔案夾」,然後在跳出來的視窗中輸入/etc/hosts
再按下前往
接著Finder就會幫你開啟對應的資料夾,應該就能看到hosts
檔案
雙擊點開之後,檔案的內容會類似下圖,不過是無法編輯的鎖定狀態
接著我們可以按照下面這篇文章的方式複製、編輯hosts
檔案
在hosts
檔案中的新的一行加入127.0.0.1 add.your.domain
⚠注意:要加入的網域,要是Step 3中,有寫在DNS.1
、DNS.2
中的,否則會沒有辦法正常運作
接著我們去瀏覽器,輸入剛剛你設定好的網域,就可以在local的瀏覽器中用custom domains存取到對應的網站啦
可喜可賀,打完收工!
Reference
- 安裝 Homebrew
- macOS 2 種安裝 OpenSSL 的方法
- Create certificate for localhost domains on macOS
- How to use local domain name instead local ip address in Mac?
- NextJS + HTTPS | For a Local Dev Server
- Create a self-signed certificate using OpenSSL
- HTTPS 什麼是根憑證 root certificate
- How to Create Trusted Self-Signed SSL Certificates and Local Domains for Testing