Let's Encrypt ์ธ์ฆ์ ์ค์น
๊ฐ์
Let's Encrypt๋ ๋ฌด๋ฃ๋ก SSL/TLS ์ธ์ฆ์๋ฅผ ๋ฐ๊ธํด์ฃผ๋ ๋น์๋ฆฌ ์ธ์ฆ ๊ธฐ๊ด(CA)์ด๋ค. Certbot ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ช
๋ น์ด ๋ช ์ค๋ก ์ธ์ฆ์ ๋ฐ๊ธ๊ณผ Nginx ์๋ ์ค์ ๊น์ง ํ ๋ฒ์ ์ฒ๋ฆฌํ ์ ์๋ค.
์์ ์ค์ต์์ ๊ตญ๋ฃฐ.com์ ๋ด ์๋ฒ์ ์ฐ๊ฒฐํ์ด์. ๊ทธ๋ฐ๋ฐ ์ง๊ธ์ http://๊ตญ๋ฃฐ.com (HTTP)์ผ๋ก๋ง ์ ์ํ ์ ์์ด์. 
์ธ์ฆ์๋ฅผ ์ค์นํ๋ฉด https://๊ตญ๋ฃฐ.com (HTTPS)์ผ๋ก ์ ์ํ ์ ์๊ณ , ๋ธ๋ผ์ฐ์ ์ ์๋ฌผ์
๊ฐ ์๊ฒจ์!
HTTPS๊ฐ ํ์ํ ์ด์ :
โข
โข
โข
โข
์ธ์ฆ์ ๋ฐ๊ธ ์ ์ฒด ํ๋ฆ
sequenceDiagram
participant Certbot as ๐ค Certbot
participant LE as ๐๏ธ Let's Encrypt CA
participant Nginx as ๐ฅ๏ธ Nginx ์๋ฒ
Certbot->>LE: ๊ตญ๋ฃฐ.com ์ธ์ฆ์ ๋ฐ๊ธ ์์ฒญ
LE-->>Certbot: ๋๋ฉ์ธ ์์ ์ฆ๋ช
์ฑ๋ฆฐ์ง ๋ฐ๊ธ
Certbot->>Nginx: /.well-known/acme-challenge/ ์ ํ์ผ ๋ฐฐ์น
LE->>Nginx: ์ฑ๋ฆฐ์ง ํ์ผ ํ์ธ (๋๋ฉ์ธ ์์ ๊ฒ์ฆ)
LE-->>Certbot: ๊ฒ์ฆ ์๋ฃ! ์ธ์ฆ์ ๋ฐ๊ธ
Certbot->>Nginx: Nginx ์ค์ ์๋ ์์ (HTTPS ๋ธ๋ก ์ถ๊ฐ)
Note over Nginx: 443 ํฌํธ๋ก HTTPS ์๋น์ค ์์Mermaid
๋ณต์ฌ
Certbot ์ค์น ๋ฐฉ๋ฒ ๋น๊ต
๋ฐฉ๋ฒ | ๋ช
๋ น์ด | ์ถ์ฒ ์ฌ๋ถ |
snap (๊ถ์ฅ) | snap install --classic certbot | |
apt (Ubuntu) | apt install certbot python3-certbot-nginx | |
pip | pip install certbot |
1๋จ๊ณ: Certbot ์ค์น
# 1. snap์ผ๋ก certbot ์ค์น (Ubuntu 20.04 ์ด์ ๊ถ์ฅ)
sudo snap install --classic certbot
# 2. certbot ๋ช
๋ น์ด PATH ๋ฑ๋ก
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# 3. ์ค์น ํ์ธ
certbot --version
# ๊ฒฐ๊ณผ ์์: certbot 2.x.x
Bash
๋ณต์ฌ
2๋จ๊ณ: ๋ฐฉํ๋ฒฝ ํฌํธ 443 ์ด๊ธฐ
HTTPS๋ 443 ํฌํธ๋ฅผ ์ฌ์ฉํด์. ์์ ์ค์ต์์ 80 ํฌํธ๋ ์ด์์ผ๋, 443๋ ์ถ๊ฐ๋ก ์ด์ด์ค์ผ ํด์!
# 443 ํฌํธ ํ์ฉ
sudo ufw allow 443/tcp
sudo ufw reload
# ํ์ธ
sudo ufw status
# ๊ฒฐ๊ณผ ์์
# 80/tcp ALLOW
# 443/tcp ALLOW โ ์ถ๊ฐ๋จ
Bash
๋ณต์ฌ
3๋จ๊ณ: ์ธ์ฆ์ ๋ฐ๊ธ
Certbot์๋ ์ฌ๋ฌ ๋ฐ๊ธ ๋ชจ๋๊ฐ ์์ด์.
graph TD
A["certbot ์คํ"] --> B{"Nginx ์ค์ <br/>์๋ ์์ ์ฌ๋ถ"}
B -->|"์๋ ์์ OK"| C["certbot --nginx<br/>(nginx ํ๋ฌ๊ทธ์ธ)"]
B -->|"์๋์ผ๋ก ์ค์ "| D["certbot certonly<br/>(์ธ์ฆ์๋ง ๋ฐ๊ธ)"]
C --> E["โ
๋ฐ๊ธ + Nginx ์ค์ ์๋ ์๋ฃ"]
D --> F["์ธ์ฆ์ ๋ฐ๊ธ ํ<br/>Nginx ์๋ ์ค์ "]
style E fill:#90EE90Mermaid
๋ณต์ฌ
๋ฐฉ๋ฒ A: Nginx ํ๋ฌ๊ทธ์ธ (์๋ ์ค์ , ์ด๋ณด์ ์ถ์ฒ)
sudo certbot --nginx -d ๊ตญ๋ฃฐ.com -d www.๊ตญ๋ฃฐ.com
Bash
๋ณต์ฌ
์คํํ๋ฉด ์๋ ์ง๋ฌธ์ด ๋์์:
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel): your@email.com โ ์ด๋ฉ์ผ ์
๋ ฅ
Please read the Terms of Service at ...
(A)gree/(C)ancel: A โ ๋์
Would you be willing to share your email address with the EFF?
(Y)es/(N)o: N โ ์ ํ
Please choose whether or not to redirect HTTP traffic to HTTPS:
1: No redirect
2: Redirect - Make all requests redirect to secure HTTPS access โ 2 ์ ํ (HTTPโHTTPS ์๋ ๋ฆฌ๋ค์ด๋ ํธ)
Select the appropriate number [1-2]: 2
Plain Text
๋ณต์ฌ
์๋ฃ ๋ฉ์์ง:
Congratulations! You have successfully enabled HTTPS on <https://๊ตญ๋ฃฐ.com>
Plain Text
๋ณต์ฌ
๋ฐฉ๋ฒ B: certonly (์ธ์ฆ์๋ง ๋ฐ๊ธ)
sudo certbot certonly --webroot \\
-w /var/www/krules \\
-d ๊ตญ๋ฃฐ.com \\
-d www.๊ตญ๋ฃฐ.com
Bash
๋ณต์ฌ
4๋จ๊ณ: ๋ฐ๊ธ๋ ์ธ์ฆ์ ํ์ธ
# ์ธ์ฆ์ ๋ชฉ๋ก ํ์ธ
sudo certbot certificates
# ๊ฒฐ๊ณผ ์์
# Found the following certs:
# Certificate Name: ๊ตญ๋ฃฐ.com
# Domains: ๊ตญ๋ฃฐ.com www.๊ตญ๋ฃฐ.com
# Expiry Date: 2026-07-21 (VALID: 89 days)
# Certificate Path: /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/fullchain.pem
# Private Key Path: /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/privkey.pem
Bash
๋ณต์ฌ
์ธ์ฆ์ ํ์ผ ๊ตฌ์กฐ
/etc/letsencrypt/live/๊ตญ๋ฃฐ.com/
โโโ fullchain.pem โ ์ธ์ฆ์ (์๋ฒ ์ธ์ฆ์ + ์ฒด์ธ ์ธ์ฆ์)
โโโ privkey.pem โ ๊ฐ์ธํค (์ ๋ ์ธ๋ถ ๋
ธ์ถ ๊ธ์ง!)
โโโ cert.pem โ ์๋ฒ ์ธ์ฆ์๋ง
โโโ chain.pem โ ์ฒด์ธ ์ธ์ฆ์๋ง
Plain Text
๋ณต์ฌ
ํ์ผ | ์ญํ | Nginx ์ค์ |
fullchain.pem | ์ธ์ฆ์ ์ ์ฒด ์ฒด์ธ | ssl_certificate |
privkey.pem | ๊ฐ์ธ ํค | ssl_certificate_key |
5๋จ๊ณ: Nginx ์ค์ ํ์ธ (certonly ์ฌ์ฉ ์ ์๋ ์ค์ )
certbot --nginx๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์๋ ์ค์ ์ด ์๋ฃ๋ผ์. certonly๋ฅผ ์ฌ์ฉํ๋ค๋ฉด Nginx ์ค์ ์ ์ง์ ์์ ํด์ผ ํด์.
sudo nano /etc/nginx/conf.d/krules.conf
Bash
๋ณต์ฌ
# ============================================
# HTTP โ HTTPS ๋ฆฌ๋ค์ด๋ ํธ
# ============================================
server {
listen 80;
server_name ๊ตญ๋ฃฐ.com www.๊ตญ๋ฃฐ.com;
return 301 https://$server_name$request_uri;
}
# ============================================
# HTTPS ์๋ฒ
# ============================================
server {
listen 443 ssl http2;
server_name ๊ตญ๋ฃฐ.com www.๊ตญ๋ฃฐ.com;
# ์ธ์ฆ์ ๊ฒฝ๋ก
ssl_certificate /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/privkey.pem;
# SSL ๋ณด์ ์ค์
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# ์ฌ์ดํธ ๋ฃจํธ
root /var/www/krules;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# ์ ์ ํ์ผ ์บ์ฑ
location ~* \\.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# ๋ก๊ทธ
access_log /var/log/nginx/krules_access.log;
error_log /var/log/nginx/krules_error.log warn;
}
Plain Text
๋ณต์ฌ
# ์ค์ ํ
์คํธ ํ ์ ์ฉ
sudo nginx -t
sudo systemctl reload nginx
Bash
๋ณต์ฌ
6๋จ๊ณ: ์๋ ๊ฐฑ์ ์ค์
Let's Encrypt ์ธ์ฆ์ ์ ํจ๊ธฐ๊ฐ์ 90์ผ์ด์์. ๋ง๋ฃ ์ ์ ์๋์ผ๋ก ๊ฐฑ์ ๋๋๋ก ์ค์ ํด์ผ ํด์!
graph LR
A["โฐ cron/systemd timer<br/>ํ๋ฃจ 2๋ฒ ์คํ"] --> B["certbot renew ๋ช
๋ น ์คํ"]
B --> C{"๋ง๋ฃ 30์ผ ์ด๋ด?"}
C -->|"Yes"| D["์ธ์ฆ์ ์๋ ๊ฐฑ์ "]
C -->|"No"| E["๊ฐฑ์ ๋ถํ์, ๊ฑด๋๋"]
D --> F["Nginx ์๋ ๋ฆฌ๋ก๋"]
style D fill:#90EE90
style E fill:#E0E0E0Mermaid
๋ณต์ฌ
Certbot ์๋ ๊ฐฑ์ ํ์ธ
# snap์ผ๋ก ์ค์นํ๋ค๋ฉด ์๋ ํ์ด๋จธ๊ฐ ์ด๋ฏธ ๋ฑ๋ก๋ผ ์์ด์!
systemctl status snap.certbot.renew.timer
# ๊ฒฐ๊ณผ ์์
# โ snap.certbot.renew.timer
# Active: active (waiting) โ ์ ์!
Bash
๋ณต์ฌ
์๋ ๊ฐฑ์ ํ ์คํธ (์ค์ ๊ฐฑ์ ์์ด ํ ์คํธ๋ง)
sudo certbot renew --dry-run
# ๊ฒฐ๊ณผ ์์
# Congratulations, all simulated renewals succeeded:
# /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/fullchain.pem (success)
Bash
๋ณต์ฌ
cron์ผ๋ก ์๋ ๋ฑ๋ก (snap ํ์ด๋จธ๊ฐ ์๋ ๊ฒฝ์ฐ)
sudo crontab -e
# ์๋ ์ค ์ถ๊ฐ (๋งค์ผ ์๋ฒฝ 3์์ ๊ฐฑ์ ์๋)
0 3 * * * certbot renew --quiet && systemctl reload nginx
Bash
๋ณต์ฌ
์ค์ต: ๊ตญ๋ฃฐ.com HTTPS ์ ์ฉ
flowchart TD
A["๐ ์ค์ต ์์<br/>(HTTP ์ฐ๊ฒฐ ์๋ฃ ์ํ)"] --> B["1. snap certbot ์ค์น"]
B --> C["2. ufw allow 443"]
C --> D["3. certbot --nginx<br/>-d ๊ตญ๋ฃฐ.com -d www.๊ตญ๋ฃฐ.com"]
D --> E{"๋ฐ๊ธ ์ฑ๊ณต?"}
E -->|"No"| F["์ค๋ฅ ํ์ธ<br/>(DNS, ๋ฐฉํ๋ฒฝ ์ ๊ฒ)"]
E -->|"Yes"| G["4. nginx -t ํ์ธ"]
F --> D
G --> H["5. systemctl reload nginx"]
H --> I["6. ๋ธ๋ผ์ฐ์ ์์<br/><https://๊ตญ๋ฃฐ.com> ์ ์"]
I --> J["7. certbot renew --dry-run<br/>์๋ ๊ฐฑ์ ํ
์คํธ"]
J --> K["โ
HTTPS ์๋ฃ! ๐"]
style K fill:#90EE90
style F fill:#FFB366Mermaid
๋ณต์ฌ
์ค์ต ํ๊ฒฝ
ํญ๋ชฉ | ๊ฐ |
๋๋ฉ์ธ | ๊ตญ๋ฃฐ.com, www.๊ตญ๋ฃฐ.com |
์ฌ์ดํธ ๋ฃจํธ | /var/www/krules |
์ธ์ฆ์ ๊ฒฝ๋ก | /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/ |
HTTP ํฌํธ | 80 (443์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ) |
HTTPS ํฌํธ | 443 |
ํธ๋ฌ๋ธ์ํ
์ฆ์ | ์์ธ | ํด๊ฒฐ |
Challenge failed for domain | DNS๊ฐ ์์ง ์๋ฒ๋ฅผ ํฅํ์ง ์์ | nslookup ๊ตญ๋ฃฐ.com์ผ๋ก IP ํ์ธ |
Connection refused | ๋ฐฉํ๋ฒฝ 443 ํฌํธ ๋ฏธ๊ฐ๋ฐฉ | ufw allow 443 |
Too many certificates already issued | ๋จ๊ธฐ๊ฐ ๋๋ฌด ๋ง์ด ๋ฐ๊ธ | 1์ฃผ์ผ ํ ์ฌ์๋ (์ฃผ 5ํ ์ ํ) |
์ธ์ฆ์ ๊ฐฑ์ ์คํจ | ํฌํธ 80์ด ๋งํ์์ | ๊ฐฑ์ ์ 80 ํฌํธ ํ์ |
ssl_certificate ์ค๋ฅ | ํ์ผ ๊ฒฝ๋ก ์คํ | ls /etc/letsencrypt/live/ ํ์ธ |
์ฒดํฌ๋ฆฌ์คํธ
certbot --version ์ผ๋ก ์ค์น ํ์ธ?
๋ฐฉํ๋ฒฝ 443 ํฌํธ ์ด๋ฆผ? (ufw status)
certbot --nginx -d ๊ตญ๋ฃฐ.com -d www.๊ตญ๋ฃฐ.com ๋ฐ๊ธ ์ฑ๊ณต?
์ด๋ฉ์ผ ์
๋ ฅ ๋ฐ ์ฝ๊ด ๋์ ์๋ฃ?
HTTP โ HTTPS ๋ฆฌ๋ค์ด๋ ํธ ์ ํ (์ต์
2)?
/etc/letsencrypt/live/๊ตญ๋ฃฐ.com/ ๋๋ ํ ๋ฆฌ ์กด์ฌ?
nginx -t ํต๊ณผ?
systemctl reload nginx ์๋ฃ?
๋ธ๋ผ์ฐ์ ์์ https://๊ตญ๋ฃฐ.com ์๋ฌผ์
ํ์ธ?
certbot renew --dry-run ์ฑ๊ณต?
์๋ ๊ฐฑ์ ํ์ด๋จธ ํ์ฑํ ํ์ธ? (systemctl status snap.certbot.renew.timer)
์ค์ต
# ============================================================
# Let's Encrypt ์ธ์ฆ์ ์ค์น ์ค์ต
# ๋๋ฉ์ธ: ๊ตญ๋ฃฐ.com / ์ฌ์ดํธ ๋ฃจํธ: /var/www/krules
# ============================================================
# [1] certbot ์ค์น
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
# ์ค์น ํ์ธ
certbot --version
# ============================================================
# [2] ๋ฐฉํ๋ฒฝ 443 ํฌํธ ์ด๊ธฐ
sudo ufw allow 443/tcp
sudo ufw reload
sudo ufw status
# ============================================================
# [3] ์ธ์ฆ์ ๋ฐ๊ธ (Nginx ์ค์ ์๋ ์์ )
# - ์ด๋ฉ์ผ ์
๋ ฅ โ A(๋์) โ N(๋ด์ค๋ ํฐ) โ 2(HTTPโHTTPS ๋ฆฌ๋ค์ด๋ ํธ)
sudo certbot --nginx -d ๊ตญ๋ฃฐ.com -d www.๊ตญ๋ฃฐ.com
# ============================================================
# [4] ๋ฐ๊ธ๋ ์ธ์ฆ์ ํ์ธ
sudo certbot certificates
# ๊ฒฐ๊ณผ์์ ์๋ ํญ๋ชฉ ํ์ธ:
# Domains: ๊ตญ๋ฃฐ.com www.๊ตญ๋ฃฐ.com
# Expiry Date: (89์ผ ์ด์)
# Certificate Path: /etc/letsencrypt/live/๊ตญ๋ฃฐ.com/fullchain.pem
# ============================================================
# [5] Nginx ์ค์ ํ
์คํธ ๋ฐ ์ ์ฉ
sudo nginx -t
sudo systemctl reload nginx
# ============================================================
# [6] ์๋ ๊ฐฑ์ cron ๋ฑ๋ก ํ์ธ (apt ์ค์น ์ ์๋ ๋ฑ๋ก๋จ)
cat /etc/cron.d/certbot
# ์๋ ๊ฐฑ์ ์๋ฎฌ๋ ์ด์
ํ
์คํธ
sudo certbot renew --dry-run
# "all simulated renewals succeeded" ๋ฉ์์ง๊ฐ ๋์ค๋ฉด ์ฑ๊ณต!
# ============================================================
# [7] ์ต์ข
ํ์ธ โ ๋ธ๋ผ์ฐ์ ์์ https://๊ตญ๋ฃฐ.com ์ ์ ํ
# ์ฃผ์์ฐฝ ์๋ฌผ์ ๐ ํ์ธ!
curl -I https://๊ตญ๋ฃฐ.com
# HTTP/2 200 ์ด ๋์ค๋ฉด HTTPS ์ ์ ๋์!
Bash
๋ณต์ฌ
ํต์ฌ ์ ๋ฆฌ
Let's Encrypt = ๋ฌด๋ฃ SSL ์ธ์ฆ์. 90์ผ ์ ํจ, ์๋ ๊ฐฑ์ ๊ฐ๋ฅ
Certbot = Let's Encrypt ์ธ์ฆ์๋ฅผ ์ฝ๊ฒ ๋ฐ๊ธยท๊ด๋ฆฌํ๋ ๊ณต์ ๋๊ตฌ
๋ฐ๊ธ ๋ช
๋ น = certbot --nginx -d ๋๋ฉ์ธ ํ ์ค๋ก ๋ฐ๊ธ + Nginx ์ค์ ์๋ ์๋ฃ
์ธ์ฆ์ ํ์ผ = fullchain.pem (์ธ์ฆ์) + privkey.pem (๊ฐ์ธํค)
์๋ ๊ฐฑ์ = snap ์ค์น ์ ํ์ด๋จธ ์๋ ๋ฑ๋ก. --dry-run์ผ๋ก ํ
์คํธ
HTTP โ HTTPS ๋ฆฌ๋ค์ด๋ ํธ = return 301 https://... ๋๋ Certbot์ด ์๋ ์ค์



