|
| 1 | +--- |
| 2 | +title: "Let's Encrypt로 SSL 인증서 발급받기 - Mac Mini로 홈서버 구축하기 #3" |
| 3 | +description: Let's Encrypt를 사용하여 무료 SSL 인증서를 발급받고 자동 갱신 설정하는 방법 |
| 4 | +date: 2025-07-03 20:00 +0900 |
| 5 | +categories: |
| 6 | +- Tips |
| 7 | +--- |
| 8 | + |
| 9 | +> 미리 알아야할 것: |
| 10 | +> - [Duck DNS로 DDNS 설정하기 - Mac Mini로 홈서버 구축하기 #1](/posts/duck_dns/) |
| 11 | +> - [nginx 서버 열기 - Mac Mini로 홈서버 구축하기 #2](/posts/nginx/) |
| 12 | +
|
| 13 | + |
| 14 | +이전 글에 이어서 Let's Encrypt를 사용하여 무료 SSL 인증서를 발급받는 방법을 알아보겠습니다. |
| 15 | + |
| 16 | +이 과정을 완료하면 HTTPS 보안 프로토콜을 사용하여 홈 서버에 안전하게 접근할 수 있게 됩니다. |
| 17 | + |
| 18 | +## 프로젝트 디렉터리 구조 |
| 19 | + |
| 20 | +``` |
| 21 | +nginx/ |
| 22 | +├── conf/ |
| 23 | +│ ├── nginx.conf |
| 24 | +│ └── sites-enabled/ |
| 25 | +│ └── default.conf |
| 26 | +├── html/ |
| 27 | +│ └── index.html |
| 28 | +├── logs/ |
| 29 | +│ └── nginx/ |
| 30 | +│ ├── access.log |
| 31 | +│ └── error.log |
| 32 | +├── certbot/ # ← 새로 추가 |
| 33 | +│ ├── www/ # /.well-known/acme-challenge 파일 저장 |
| 34 | +│ └── letsencrypt/ # /etc/letsencrypt 실제 인증서 |
| 35 | +└── docker-compose.yml |
| 36 | +``` |
| 37 | + |
| 38 | +- **certbot/www**: 웹루트 플러그인용 챌린지 파일을 저장하는 디렉터리 |
| 39 | +- **certbot/letsencrypt**: live/, archive/, renewal/ 하위 디렉터리를 포함한 Certbot 기본 구조를 보관하는 디렉터리 |
| 40 | + |
| 41 | +이렇게 독립된 폴더를 구성하면 컨테이너를 교체해도 인증서와 챌린지 파일이 보존됩니다. |
| 42 | + |
| 43 | +## 수정된 docker-compose.yml |
| 44 | + |
| 45 | +```yaml |
| 46 | +services: |
| 47 | + nginx: |
| 48 | + image: nginx:latest |
| 49 | + container_name: my-nginx |
| 50 | + ports: |
| 51 | + - "80:80" |
| 52 | + - "443:443" |
| 53 | + volumes: |
| 54 | + - ./html:/usr/share/nginx/html:ro |
| 55 | + - ./conf/nginx.conf:/etc/nginx/nginx.conf:ro |
| 56 | + - ./conf/sites-enabled:/etc/nginx/conf.d:ro |
| 57 | + - ./logs/nginx:/var/log/nginx |
| 58 | + - ./certbot/www:/var/www/certbot # 웹루트 공유 |
| 59 | + - ./certbot/letsencrypt:/etc/letsencrypt # 인증서 공유 |
| 60 | + restart: unless-stopped |
| 61 | + |
| 62 | + certbot: |
| 63 | + image: certbot/certbot:latest |
| 64 | + container_name: certbot |
| 65 | + depends_on: |
| 66 | + - nginx |
| 67 | + volumes: |
| 68 | + - ./certbot/www:/var/www/certbot |
| 69 | + - ./certbot/letsencrypt:/etc/letsencrypt |
| 70 | + restart: "no" |
| 71 | +``` |
| 72 | +
|
| 73 | +Nginx 설정에서 `/var/www/certbot`을 루트로 지정한 `location /.well-known/acme-challenge/` 블록을 반드시 포함해야 합니다. |
| 74 | + |
| 75 | +Certbot 서비스는 상시 실행할 필요가 없으므로 `restart: "no"`로 설정하고, 인증서 발급 및 갱신 시에만 `docker compose run`으로 호출합니다. |
| 76 | + |
| 77 | +## 최초 인증서 발급 절차 |
| 78 | + |
| 79 | +### 1단계: nginx 설정 파일 수정 |
| 80 | + |
| 81 | +`conf/sites-enabled/default.conf` 파일에 다음 내용을 추가해야 합니다: |
| 82 | + |
| 83 | +```nginx |
| 84 | +server { |
| 85 | + listen 80; # 수신 포트 (HTTP 기본 80) |
| 86 | + server_name your-domain.duckdns.org; |
| 87 | + root /usr/share/nginx/html; |
| 88 | + index index.html index.htm; # 기본 문서 |
| 89 | +
|
| 90 | + # ACME 챌린지용 경로 |
| 91 | + location /.well-known/acme-challenge/ { |
| 92 | + root /var/www/certbot; |
| 93 | + } |
| 94 | +
|
| 95 | + # 기본 정적 파일 서빙 |
| 96 | + location / { |
| 97 | + try_files $uri $uri/ =404; |
| 98 | + } |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +### 2단계: 인증서 발급 |
| 103 | + |
| 104 | +```bash |
| 105 | +# HTTP 모드로 Nginx만 우선 기동 |
| 106 | +docker compose up -d nginx |
| 107 | +
|
| 108 | +# 인증서 최초 발급 (웹루트 방식) |
| 109 | +# ⚠️ docker-compose.yml의 certbot command를 제거하고 아래 명령어를 사용하세요 |
| 110 | +docker compose run --rm certbot certonly \ |
| 111 | + --webroot -w /var/www/certbot \ |
| 112 | + -d your-domain.duckdns.org \ |
| 113 | + --email [email protected] --agree-tos --no-eff-email |
| 114 | +``` |
| 115 | + |
| 116 | +발급이 완료되면 `certbot/letsencrypt/live/your-domain.duckdns.org/{fullchain.pem,privkey.pem}` 파일이 생성됩니다. |
| 117 | + |
| 118 | +## HTTPS 설정 추가 |
| 119 | + |
| 120 | +인증서 발급이 완료되면 nginx 설정을 HTTPS로 업데이트해야 합니다: |
| 121 | + |
| 122 | +```nginx |
| 123 | +server { |
| 124 | + listen 80; |
| 125 | + server_name your-domain.duckdns.org; |
| 126 | + |
| 127 | + # ACME 챌린지용 경로 |
| 128 | + location /.well-known/acme-challenge/ { |
| 129 | + root /var/www/certbot; |
| 130 | + } |
| 131 | + |
| 132 | + # HTTP를 HTTPS로 리다이렉트 |
| 133 | + location / { |
| 134 | + return 301 https://$host$request_uri; |
| 135 | + } |
| 136 | +} |
| 137 | +
|
| 138 | +server { |
| 139 | + listen 443 ssl; |
| 140 | + server_name your-domain.duckdns.org; |
| 141 | + |
| 142 | + ssl_certificate /etc/letsencrypt/live/your-domain.duckdns.org/fullchain.pem; |
| 143 | + ssl_certificate_key /etc/letsencrypt/live/your-domain.duckdns.org/privkey.pem; |
| 144 | + |
| 145 | + location / { |
| 146 | + root /usr/share/nginx/html; |
| 147 | + index index.html; |
| 148 | + } |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +설정 변경 후 nginx를 재시작합니다: |
| 153 | + |
| 154 | +```bash |
| 155 | +docker compose restart nginx |
| 156 | +``` |
| 157 | + |
| 158 | +## crontab으로 자동 갱신 |
| 159 | + |
| 160 | +### 크론 항목 예시 (macOS 또는 Linux 호스트) |
| 161 | + |
| 162 | +```bash |
| 163 | +# 매일 03:00에 갱신 시도 |
| 164 | +# ⚠️ /path/to/nginx를 실제 nginx 프로젝트 경로로 변경하세요 |
| 165 | +00 3 * * * cd /path/to/nginx && \ |
| 166 | + docker compose run --rm certbot renew --webroot -w /var/www/certbot --quiet && \ |
| 167 | + docker compose exec nginx nginx -s reload |
| 168 | +``` |
| 169 | + |
| 170 | +Let's Encrypt 커뮤니티와 Certbot 문서에서는 하루 1~2회 호출을 권장합니다. `renew` 명령은 30일 이하로 만료되는 인증서만 실제로 갱신하므로 서버 부담이 적습니다. |
| 171 | + |
| 172 | + |
| 173 | +## 주의사항 |
| 174 | + |
| 175 | +1. **도메인 이름 변경**: 위 예시의 `your-domain.duckdns.org`를 실제 사용하는 도메인으로 변경하세요. |
| 176 | +2. **이메일 주소 변경**: `[email protected]`을 실제 이메일 주소로 변경하세요. |
| 177 | +3. **경로 확인**: crontab의 `/path/to/nginx`를 실제 nginx 프로젝트 경로로 변경하세요. |
| 178 | +4. **포트 확인**: 방화벽에서 80번과 443번 포트가 열려있는지 확인하세요. |
0 commit comments