홈서버 (재)구축하기 - 3. 웹서버 구성 (1)
ddclient로 DDNS 설정, letsencrypt & certbot으로 SSL 인증서 발급 및 자동 갱신 설정하기
Cloudflare의 Global API Key 받기
오늘 다룰 두 서비스는 DNS에 레코드를 추가, 변경하는 작업을 자동화하므로 DNS의 API 키가 필요하다. 필자가 사용하고 있는 Cloudflare를 기준으로 작성한다.
DDNS 설정 - ddclient
홈서버는 가정용 인터넷 망을 사용하며, 기업과 달리 서버 운용을 염두해두지 않기 때문에 IP가 고정이 아니다. 따라서 기기가 IP를 오랫동안 점유하지 않거나, 점유를 하더라도 오랜 시간이 지나면 할당한 IP를 회수하기도 한다.
내가 보유한 도메인으로 내 서버에 접속하려면 도메인 서버에 레코드를 등록하여 도메인과 IP를 연결해야한다. 위의 이유로 IP가 바뀌게 된다면 레코드에 기록된 IP와 서버의 실제 IP가 달라지므로 서버를 접속할 수 없게 된다. 이럴 때 필요한 것이 DDNS(Dynamic Domain Name Server)다.
DDNS를 설정할 수 있는 공유기 제품이 있지만, 지금 사용 중인 공유기는 그런 기능이 없어서 서버에 DDNS 클라이언트를 설치하고자 한다. ddclient
는 이러한 클라이언트 중 하나로, DNS 계정(혹은 API)를 통해 DDNS를 쉽게 구성할 수 있게 해준다.
ddclient
는 다양한 DNS를 지원하고 있으나 한국의 DNS는 지원하지 않는다. 필자는 Cloudflare를 사용하므로 이를 기준으로 작성한다.
설치
- 패키지 목록을 업데이트 후 설치
1 2
$ sudo apt update $ sudo apt install ddclient
아이디, Global API Key 입력
Cloudflare을 로그인할 때 사용하는 이메일을 입력한다.
아까 발급한 Global API Key를 입력한다.
IP를 받아올 방식 선택
서버가 공유기와 방화벽을 거치므로 Web-based IP discovery service(웹 기반 IP 탐색)을 선택한다.
- 실행 확인
1
$ sudo service ddclient status
위 명령어로 ddclient가 잘 작동하는지 확인해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
● ddclient.service - Update dynamic domain name service entries Loaded: loaded (/usr/lib/systemd/system/ddclient.service; enabled; preset: enabled) Active: active (running) since Wed 2024-12-18 17:12:47 UTC; 41min ago Docs: man:ddclient(8) Process: 9354 ExecStart=/usr/bin/ddclient -daemon $daemon_interval -syslog -pid /run/ddclient.pid (code=exited, status=0/SUCCESS) Main PID: 9359 (ddclient - slee) Tasks: 1 (limit: 18935) Memory: 11.1M (peak: 15.1M) CPU: 263ms CGroup: /system.slice/ddclient.service └─9359 "ddclient - sleeping for 210 seconds" Dec 18 17:27:47 homeserver ddclient[9528]: WARNING: skipping host: test.example.kr: 'zone=' is an invalid fully qualified host name. Dec 18 17:32:47 homeserver ddclient[9556]: WARNING: skipping host: test.example.kr: 'zone=' is an invalid fully qualified host name. Dec 18 17:37:47 homeserver ddclient[9588]: WARNING: skipping host: test.example.kr: 'zone=' is an invalid fully qualified host name. Dec 18 17:37:47 homeserver ddclient[9591]: WARNING: skipping host: test.example.com: 'zone=' is an invalid fully qualified host name. Dec 18 17:42:47 homeserver ddclient[9623]: WARNING: skipping host: test.example.kr: 'zone=' is an invalid fully qualified host name. . . .
skipping이라고 되어있으니 잘 작동하지 않는 것이다.
'zone=' is an invalid fully qualified host name.
라는 에러 메세지에서 알 수 있듯, zone과 관련된 문제가 있는 것으로 보인다.
세부 설정
ddclient의 설정은 /etc/ddclient.conf
에서 확인할 수 있다.
1
2
3
4
5
6
7
8
9
# Configuration file for ddclient generated by debconf
#
# /etc/ddclient.conf
protocol=cloudflare \
use=web, web=ipify-ipv4 \
login=my@email.com \
password='Global API Key' \
test.example.kr,test.example.com
Cloudflare는 Zone을 기준으로 도메인을 구분하고, 서브 도메인의 레코드를 수정할 수 있다. 따라서 Zone을 구분하여 파일 내용을 아래와 같이 수정한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
protocol=cloudflare \
use=web, web=http://checkip.dyndns.org/ \
zone=example.kr \
login=my@email.com \
password='Global API Key' \
test.example.kr \
protocol=cloudflare \
use=web, web=http://checkip.dyndns.org/ \
zone=example.com \
login=my@email.com \
password='Global API Key' \
test.example.com
마무리
1
2
3
$ sudo ddclient -daemon=0 -debug -verbose -noquiet
$ sudo service ddclient restart
$ sudo service ddclient status
먼저 디버그 모드로 테스트 한 후, 잘 작동한다면 ddclient를 재시작해서 설정을 반영하자.
HTTPS 적용을 위한 인증서 발급 - certbot
HTTPS는 HTTP에 SSL/TLS 암호화 프로토콜을 추가한 것으로, 클라이언트와 서버 간의 데이터가 암호화되어 도청과 데이터 탈취를 방지할 수 있다.
요즘 브라우저에서는 HTTP를 사용하면 경고를 띄워서 보기 안 좋을 뿐더러, 내가 올릴 서비스 대부분이 HTTP 환경에서는 작동이 어렵다. 따라서 certbot을 통해 무료로 발급 가능한 Let’s Encrypt의 인증서를 통해 HTTPS를 적용하고자 한다.
발급 방식에 여러가지가 있는데, 수동 발급이나 웹서버 등을 이용한 발급은 자동 갱신이 귀찮기 때문에, Cloudflare의 API를 이용해 ACME Challenge 방식으로 발급 및 자동갱신을 하고자 한다. DNS Challenge를 이용한 인증서 발급은 해당 문서를 참고했다.
certbot 설치 및 발급 진행
certbot 홈페이지에선 운영체제가 제공하는 저장소(우분투의 경우 apt
) 대신, 컨테이너로 격리된 패키지 형식을 snap
를 사용해 설치할 것을 권장한다. snap
사용법은 나중에 찾아서 정리해보겠다.
- certbot과 Cloudflare 애드온 설치
1 2 3
$ sudo snap install --classic certbot $ sudo snap set certbot trust-plugin-with-root=ok $ sudo snap install certbot-dns-cloudflare
- Global API Key를 원하는 경로에 저장하기
1 2
dns_cloudflare_email = my@email.com dns_cloudflare_api_key = 'Global API Key'
API 키를 위의 형식대로 입력해준다.
1
$ sudo chmod 600 /etc/letsencrypt/cloudflare.ini
그리고 작성자 외에 내용을 볼 수 없도록 권한을 설정한다.
- 인증서 발급하기
1 2 3 4 5 6 7
$ sudo certbot certonly \ --cert-name my-cert --dns-cloudflare \ --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \ --dns-cloudflare-propagation-seconds 15 \ -d *.example.com \ -d example.com
--cert-name my-cert
: 인증서 이름--dns-cloudflare-credentials <경로>
: API 키 경로--dns-cloudflare-propagation-seconds <초>
: DNS 레코드 업데이트까지 기다릴 시간-d <도메인>
: 인증서를 발급받을 도메인
이 방식의 경우 와일드카드 인증서도 발급이 가능하다. 발급하고 싶다면
-d *.example.com
와 같이 명령어를 추가입력하면 된다.1 2 3
Saving debug log to /var/log/letsencrypt/letsencrypt.log Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): my@email.com
인증서 만료와 보안 공지를 받을 이메일을 입력한다.
1 2 3 4 5 6
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o:
Let’s Encrypt 약관을 확인하고 동의 여부를 선택한다.
거절하면 당연히 발급이 안 된다…1 2 3 4 5
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o:
Let’s Encrypt를 관리하는 재단인 Electronic Frontier Foundation의 이메일을 받을지 선택한다.
- 인증서 발급 완료
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Account registered. Requesting a certificate for example.com and 1 more domains Waiting 15 seconds for DNS changes to propagate Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem This certificate expires on 2025-04-23. These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - If you like Certbot, please consider supporting our work by: * Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate * Donating to EFF: https://eff.org/donate-le - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
인증서가
/etc/letsencrypt/live/example.com
에 발급되었다. - 자동 갱신 테스트
1
$ sudo certbot renew --dry-run
자동 갱신에 문제가 생기지는 않는지 명령어를 실행해서 확인해보자. 문제가 있다면
/etc/letsencrypt/renewal/example.com.conf
에서 설정을 수정할 수 있다.
인증서 삭제
적용할 도메인에 오타가 났거나, 마음에 안 드는 부분이 있을 경우 삭제 후 다시 발급을 해야한다. 인증서는 아래 절차에 따라 삭제가 가능하다.
- 인증서 리스트 확인
1 2 3 4 5 6 7 8 9 10 11 12 13
$ sudo certbot certificates Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Found the following certs: Certificate Name: example.com Serial Number: *********************************** Key Type: ECDSA Domains: example.com Expiry Date: 2025-04-23 15:26:03+00:00 (VALID: 89 days) Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate Name
확인 후 인증서 삭제1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$ sudo certbot delete --cert-name [인증서 이름] Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The following certificate(s) are selected for deletion: * example.com WARNING: Before continuing, ensure that the listed certificates are not being used by any installed server software (e.g. Apache, nginx, mail servers). Deleting a certificate that is still being used will cause the server software to stop working. See https://certbot.org/deleting-certs for information on deleting certificates safely. Are you sure you want to delete the above certificate(s)? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: y Deleted all files relating to certificate example.com.
삭제 후 인증서 리스트를 다시 확인하고, 인증서를 사용하는 웹서버가 있는지 점검해본다.