[Docker] — How to setup letsencrypt on docker

RootFy22
Artisan Brain Academy
3 min readJan 30, 2020

--

สวัสดีครับ ห่างหายไปนาน เนื่องจากมีภาระกิจพอสมควร วันนี้อยากจะจดบันทึก การแก้ไขปัญหาวิธีการติดตั้ง SSL free Let’s encrypt (อันที่ทำตอนนี้ต้อง renew ทุกๆ 3 เดือนเองก่อนนะครับ) ซึ่งผมมี application รันผ่าน docker บนเครื่อง gcp ของลูกค้า และลูกค้ามีเว็บไซด์พร้อม ssl certifcation อยู่แล้ว ขอสมมติชื่อว่า https://example.com ทางทีมผมต้องการใช้ https://app.example.com แต่เนื่องจากข้อจำกัดคือ ลค. ไม่สามารถมอบ cert หรือให้ ผมเข้าไปช่วยจัดการย้าย dns ของ example.com มาที่ cloudflare (ถ้าย้ายมาใช้ ssl ได้ทันที ผมก็ไม่ต้องงมเลย T_T) เรามาลองดูวิธีแก้ปัญหากันเลยนะครับ

Step-01 ทำการติดตั้ง certbot กันก่อนนะครับตามลิงค์ด้านล่างนี้ได้เลย

Step-02 โครงสร้างการทำงานของ docker เดิมที่ใช้ประจำ

Folder structure for reverse proxy container

จากรูปปกติผมจะมีอย่างต่ำ 2 containers คือ front-end container (vuejs, react) และ back-end container (nodejs, laravel, django, golang) และมีตัวจัดการ reverse proxy อีก หนึ่ง containers โดยประกอบไปด้วย

  • conf.d เก็บไฟล์ *.conf ที่ใช้สำหรับจัดการ domain หรือ sub domain เพื่อ point ไปยัง container ต่างๆ
  • letsencrypt เป็น folder ที่เอาให้ certbot ทำการตรวจสอบข้อมูล ก่อนสร้าง ssl certifcation ให้
  • ssl เก็บไฟล์ที่ certbot สร้างให้แล้ว เพื่อเอาไว้ให้ docker จัดการ certification ของ domain / sub domain

Step-03 ตัวอย่างไฟล์ Dockerfile ที่ใช้

FROM  nginx:alpine
ADD ./ssl /etc/nginx/certs
ADD ./conf.d /etc/nginx/conf.d

Step-04 ตัวอย่างไฟล์ docker-compose.yml ที่ใช้

version: '3.3'
services:
reverse-proxy:
build: .
ports:
- 80:80
- 443:443
volumes:
- ./letsencrypt:/var/www/letsencrypt

Step-05 ตัวอย่างไฟล์ conf.d/app-example-com.conf

upstream app-front {
server app.example.com:12141;
}
server { listen 80;
server_name app.example.com;
client_max_body_size 1024M;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://front-app;
}

location ^~ /.well-known {
allow all;
alias /var/www/letsencrypt/.well-known/;
default_type "text/plain";
try_files $uri =404;
}
location ^~ /.well-known/acme-challenge/ {
allow all;
alias /var/www/letsencrypt/.well-known/acme-challenge/;
}
}

จากโจทย์เรามี container รันอยู่ ที่ port 12141 เราต้องการที่จะให้ https://app.example.com => วิ่งไปหา http://app.example.com:12141 สิ่งที่ต้องเตรียมก่อนรันคำสั่ง gen cert ของ certbot คือ ต้องสร้างโฟลเดอร์ /.well-know/acme-chalenge อยู่ในโฟลเดอร์ letsencrypt ตาม Step-02

Step-05 จากนั้นรันคำสั่งนี้บน terminal console

sudo certbot certonly \
--manual \
--agree-tos \
--webroot-path=/home/root/folder/letsencrypt \
--preferred-challenges=http \
--server https://acme-v02.api.letsencrypt.org/directory \
--email ีเมล์ \
--domains โดเมน

เราจะได้ไฟล์ทั้งหมด 4 ไฟล์ อยู่ใน /etc/letsencrypt/archive/app.example.com จากนั้นเราจะใช้แค่ 2 ไฟล์ คือ

  • privkey1.pem เปลี่ยนชื่อ เป็น app.key
  • fullchain1.pem เปลี่ยนชื่อ เป็น app.pem
ไฟล์ทั้งหมดหลังจากรัน certbot

Step-06 ย้าย app.key และ app.pem ไปไว้ใน ssl folder ตาม Step-02

Step-07 แก้ไขไฟล์ conf.d/app-example-com.conf เพิ่ม ssl เข้าไปดังนี้

upstream app-front {
server app.example.com:12141;
}
server { listen 80;
server_name app.example.com;
client_max_body_size 1024M;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://front-app;
}

}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/app.pem;
ssl_certificate_key /etc/nginx/certs/app.key;

server_name app.example.com;
client_max_body_size 1024M;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://front-app;
}
}

Step-08 จากนั้นรันคำสั่ง docker-compose up -d reverse-proxy ขึ้นมา

ถ้าสามารถเข้า https://app.example.com ได้แล้วเป็นอันว่าเราสามารถใช้ free ssl ได้อีก สาม เดือนข้างหน้าครับ

หากมีข้อสงสัย หรือแลกเปลี่ยนแนะนำ สามารถคอมเม้นท์ได้เลยนะครับ ขอบคุณมากครับ แล้วพบกันใหม่ครั้งหน้า
Happy Coding!!!

--

--