Published on
-
6 mins read

Setup HTTPS ở localhost

Authors
  • avatar
    Name
    Tuan Anh Huynh (Leo)
    Twitter
    @hta218
Photo by Dan Nelson on Unsplash
secure

Khi nào thì cần HTTPSlocal?

Problem

Trong phần lớn các trường hợp thì lúc dev local bạn không cần đến HTTPS, tuy nhiên nếu server của bạn có những tính năng cần phải authen với 1 bên thứ 3, hoặc listen 1 webhook từ bên ngoài và các bên thứ 3 này yêu cầu server của bạn cần phải có HTTPS thì mới có thể nhận request được thì bạn sẽ làm như thế nào? Tất nhiên production thì sẽ có HTTPS rồi, những khi dev ở local thì sao?

Chúng ta có thể có 1 vài lựa chọn đơn giản như sử dụng PageKite hoặc ngrok để tạo 1 HTTPS tunnel trỏ đến localhost của bạn và làm việc, nhưng những service này có 1 vài nhược điểm như:

  • Bị giới hạn về số lượng tunnel/request khi xài free

  • Không config được domain cụ thể, 1 lần sử dụng sẽ là 1 random domain => phải config lại URL mỗi lần dev

  • Và đặc biệt là chậm vl , khiến việc dev rất mất thời gian...

Nếu bạn cũng gặp các vấn đề như trên thì đây là giải pháp

Solution

Giải pháp của mình là sử dụng OpenSSL để generate các SSL certificates và tạo 1 HTTPS web server với những certificates này

Generate Root SSL Certificate

Đầu tiên, chúng ta cần tạo 1 Root SSL Certificate để sign bất kì 1 certificate nào mà chúng ta sẽ generate cho localhost.

Sử dụng command sau để tạo key dùng cho việc generate Root SSL Certificate:

$ openssl genrsa -des3 -out rootCA.key 2048
root-ca-key

Bạn sẽ được yêu cầu nhập 1 pass phrase để generate key, chỉ cần nhập string bất kì và verify lại đúng là được.

Nhớ pass phrase này để còn sử dụng để verify ở các bước sau nhé!

Key vừa tạo sẽ được save vào file rootCA.key.

Sử dụng key vừa tạo để generate Root SSL Certificate với command:

$ openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 7300 -out rootCA.pem
root-ca-pem

Tiếp tục fill các thông tin cần thiết (chú ý pass phrase phải trùng với pass phrase dùng để tạo rootCA.key ở trên thì mới được nhé!)

Certificate này sẽ được save ở file rootCA.pem.

Trust Root SSL Certificate

Để có thể sử dụng các certificate generate bởi Root SSL Certificate thì chúng ta cần OS trust cái Root Certificate này

Các bạn mở app Keychain Access, chọn tab Certificate:

keychain-access

Import rootCA.pem vừa tạo vào bằng cách kéo vào hoặc File / Import items...

Sau đó Right click / Get Info hoặc (Double click) certificate vừa import

cert-trust-setting

Mở tab Trust, ở setting đầu tiên chọn Always Trust, sau đó save lại.

Khi xong xuôi thì ở Keychain Access sẽ hiện message "This certificate is marked as trusted for this account" có nghĩa là chúng ta đã trust thành công Root SSL Certificate nhé

Tạo SSL Certificate cho localhost

Bây giờ chúng ta sẽ sử dụng Root SSL Certificate đã trust để generate 1 SSL Certificate cho localhost.

Step 1

Tạo 1 file config cho OpenSSL để generate Certificate key với file name là server.csr.cnf

server.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=US
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = localhost

Tạo Certificate key với config trên và lưu vào file server.key:

$ openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config <( cat server.csr.cnf )
server-key

Step 2

Tạo file v3.ext với config sau để generate certificate:

v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost

Generate certificate với Root SSL Certificate tạo bên trên và v3.ext config rồi lưu vào file server.crt bằng command:

$ openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 825 -sha256 -extfile v3.ext

Chú ý nhập đúng pass phrase từ các bước trên

server-cert

Done

Bây giờ trong folder mà bạn vừa tạo certificate sẽ chứa 2 file server.keyserver.crt, chúng ta sẽ dùng 2 file này để tạo HTTPS server ở bước tiếp theo.

cert-folder

Tạo HTTPS server

Việc quan trọng nhất là tạo server.keyserver.crt đã xong.

Bây giờ mình sẽ hướng dẫn các bạn sử dụng certificate này để tạo 1 HTTPS server ở localhost với Node.js sử dụng Koa.js framework (Express hoàn toàn tương tự nhé, vì Koa được tạo ra từ team Express )

Tạo 1 server đơn giản với Koa:

server.js
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello World';
});
module.exports = app

Tạo folder certs/ trong server của bạn, chuyển 2 file server.keyserver.crt vào.

Load certificates file và tạo HTTPS server với https module:

index.js
const app = require('./server')
const https = require('https')
const fs = require('fs')
const path = require('path')
let certOptions = null
try {
certOptions = {
key: fs.readFileSync(path.resolve('certs/server.key')),
cert: fs.readFileSync(path.resolve('certs/server.crt'))
}
} catch(err) {
console.log('No certificate files found!')
}
const host = process.env.APP_URL || 'localhost'
const isLocal = host === 'localhost'
const enableHTTPSInLocal = Boolean(isLocal && certOptions)
const port = enableHTTPSInLocal ? 443 : process.env.PORT || 3434
const protocol = (isLocal && !certOptions) ? "http" : "https"
const url = `${protocol}://${host}${isLocal ? `:${port}` : ''}`
const callback = () => {
console.log(`App start successfully at ${url}`)
}
if (enableHTTPSInLocal) {
https
.createServer(certOptions || {}, app.callback())
.listen(port, callback)
} else {
app.listen(port, callback)
}

Project structure sẽ trông như thế này:

https-koa-project

Start server với npm start ( chú ý là node index.js chứ k phải node server.js nhé!)

http-koa

Nếu không có certificate file thì sẽ chạy http như bình thường.

https-koa

Và khi có certificate file thì app sẽ start ở port 443 với HTTPS

localhost-443

Mở https://localhost:443 là sẽ thấy có HTTPS ở localhost rồi nhé

Toàn bộ source code mình để ở repo này

Kết bài

Nếu các bạn không sử dụng Node.js thì tự google cách tạo HTTPS server với certificate files ở ngôn ngữ/công nghệ mà bạn sử dụng nhé

Hi vọng tutorial này giúp ích cho bạn trong việc dev ở local với HTTPS!

Happy sharing

Refs