Let’s Encrypt로 무료 SSL 인증서 발급하기 (우분투, nginx 활용)
1. Apps Script 와 SSL 인증서
구글 앱스 스크립트에서 UrlFetchApp을 통해서 API를 호출하는 경우, 상용으로 제공되는 서비스의 경우에는 별다른 문제가 생기지 않습니다. 대부분의 상용 API는 HTTPS로 보안을 제공하기 때문에 불편함 없이 사용할 수 있습니다.
하지만, 직접 서버를 개발해서 API를 만드는 경우, IP주소로 된 경로로 API를 호출하는 경우에는 앱스 스크립트의 보안 정책상 호출이 되지 않는 것을 경험할 수 있습니다. POSTMAN을 사용해서 API를 호출하는 경우에는 문제가 없을 수 있지만, 앱스 스크립트에서 호출하면 SSL Error 가 발생하게 됩니다. API를 호출할 때 옵션으로 다음 매개변수를 추가하면 SSL 이 없이도 호출이 성공하기는 합니다.
1 |
'validateHttpsCertificates' : false |
그렇지만, 보안상으로는 좋지 않으니 SSL을 설치하는 것이 좋겠지요? 구글에서는 openssl 로 생성한 인증서는 안전하지 않은 것으로 판단하기 때문에 Let’s Encrypt를 사용해서 구글에서도 안전하다고 판단하는 인증서를 적용해보겠습니다.
Let’s Encrypt – 무료 SSL/TLS 인증서
2. DNS 설정: 도메인과 서버IP 연결
Let’s Encrypt 인증서는 IP주소만으로는 발급받을 수 없기 때문에 도메인이 있어야 합니다. 포스트에서는 가비아에서 구입한 도메인을 가비아의 우분투 서버에 연결합니다. 가비아를 기준으로 DNS 설정을 하는 방법을 설명하겠습니다. 다른 서비스도 유사하게 설정하면 됩니다.
먼저, 가비아의 My가비아 메뉴로 들어가면 DNS 관리툴이 있습니다.

DNS 관리에 들어가면 구입한 도메인의 목록이 나옵니다. 연결할 도메인의 오른쪽의 설정을 눌러서 들어갑니다.

도메인의 DNS 설정에서 레코드 수정을 클릭합니다. 타입은 A로, 호스트는 www로 입력하고 값/위치에 서버의 IP를 입력해줍니다. 서브도메인을 사용하려는 경우에는 호스트를 www가 아니라 원하는 서브도메인으로 입력할 수 있습니다. 저장하고 1시간 ~ 48시간 내에 정상적으로 작동을 합니다.
잘 연결되었는지는 터미널에서 nslookup 도메인명
으로 확인할 수 있습니다.


3. 서버 기본 설정
도메인을 서버로 연결을 해두었으니, 이제 서버에서 Let’s Encrypt SSL 인증서를 발급하기 위해 기본 설정을 진행합시다.
서버에 터미널로 접속해서 필요한 패키지를 설치합니다.
- nginx 웹 서버를 설치하면 2번째 단계에서 도메인을 IP로 연결한 뒤에 도메인으로 접속할 수 있도록 만들어줍니다.
- Let’s Encrypt 는 certbot 패키지로 인증서를 발급받는데, nginx를 함께 사용합니다. 관련된 플러그인도 함께 설치해줍니다.
1 2 |
sudo apt install nginx # nginx 웹 서버 설치 sudo apt install -y certbot python3-certbot-nginx # Certbot 및 nginx 플러그인 설치 |
여기까지 정상적으로 진행이 되었다면, 자신의 http://www.도메인
으로 접속했을 때에 다음과 같은 nginx의 환영메시지가 표시됩니다.

4. Let’s Encrypt SSL 인증서 발급
이제 도메인에 SSL 인증서를 발급할 준비가 되었습니다.
인증서를 발급하면서 자동으로 nginx의 설정도 변경해주는 방식으로 진행합니다. 아래와 같이 터미널에 입력하면, 지정한 도메인으로 SSL 인증서를 발급하고, nginx 의 설정을 바꿔줍니다.
- http:// 로 접근하면 https:// 로 리다이렉트 합니다.
- SSL 인증서의 경로를 추가해서 https를 활성화해줍니다.
1 |
sudo certbot --nginx -d www.domain.com # www.domain.com은 자신의 도메인입니다. |
정상적으로 진행이 되면, 인증서 발급이 잘 되었다는 다음과 같은 메시지를 볼 수 있습니다.
1 2 3 4 |
Congratulations! You have successfully enabled <https://www.domain.com> You should test your configuration at: <https://www.ssllabs.com/ssltest/analyze.html?d=www.domain.com> |
nginx의 설정 파일이 변경되었기 때문에 nginx를 재시작 해줍니다.
1 |
sudo systemctl restart nginx |
이제 브라우저에서 http로 접속하면 https로 리다이렉트 되며, 사이트가 안전하다고 표시됩니다.

🔄 인증서 자동 갱신
다음과 같이 certbot 의 renew 를 시뮬레이션 해볼 수 있습니다. 코드가 성공하면 갱신이 정상적으로 될 것으로 기대할 수 있습니다.
1 |
sudo certbot renew --dry-run |
자동 갱신 설정은 처음에 발급받을 때 자동으로 되는데, 다음 명령어로 예약이 되어 있는지 확인할 수 있습니다.
1 |
sudo systemctl list-timers | grep certbot |
정상적으로 예약된 결과 입니다.
1 2 3 4 |
Thu 2025-02-06 17:15:31 KST 2h 57min left Thu 2025-02-06 01:05:05 KST 13h ago certbot.timer certbot.service |
⚠️ 인증서 발급 오류가 발생하는 경우 대처 방법
도메인과 서버가 연결이 되었고, http로 접속도 되는 것을 확인했지만, Let’s Encrypt로 SSL 인증서를 발급하는 중에 다음과 같은 오류가 나서 발급이 실패할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Performing the following challenges: http-01 challenge for www.domain.com Waiting for verification... Challenge failed for domain www.domain.com http-01 challenge for www.domain.com Cleaning up challenges Some challenges have failed. IMPORTANT NOTES: - The following errors were reported by the server: Domain: www.domain.com Type: connection Detail: During secondary validation: 139.150.68.133: Fetching <http://www.domain.com/.well-known/acme-challenge/3a8SOltmYhB4RDkLMUZKHWDl5CJApmLmkSFqGdekVjE:> Timeout during connect (likely firewall problem) To fix these errors, please make sure that your domain name was entered correctly and the DNS A/AAAA record(s) for that domain contain(s) the right IP address. Additionally, please check that your computer has a publicly routable IP address and that no firewalls are preventing the server from communicating with the client. If you're using the webroot plugin, you should also verify that you are serving files from the webroot path you provided. |
오류 내용에서 명시된 것처럼 방화벽 설정이 문제인 경우가 있습니다.
가비아 서버의 경우 웹 콘솔에서 방화벽을 세팅하는 부분이 있습니다.

설정 항목을 보면 허용 국가가 있습니다.
일반적으로 앱스 스크립트가 호출하도록 하려면 미국만 열어두면 됩니다. 하지만 Let’s Encrypt로 인증서를 받고자 한다면 몇몇 국가를 열어둘 필요성이 있습니다. 다음과 같은 국가를 허용으로 바꾸고 인증서 발급을 다시 진행한다면 성공할 것입니다.
1 2 3 4 5 6 7 |
미국 독일 영국 스웨덴 프랑스 네덜란드 싱가포르 |

이제 도메인에 SSL 인증서가 적용되어서 앱스 스크립트에서 신뢰할 수 있도록 변경되었습니다. 앱스 스크립트에서 신뢰할 수 있는 도메인으로 인식하는 것은 특히 트리거를 사용하는 경우에 중요합니다.
사용자가 직접 앱스 스크립트를 실행하는 경우에는 SSL 인증서가 적용되지 않은 주소로도 호출하는 것이 가능하지만, 트리거를 사용하는 경우에는 구글에서 더 엄격한 보안을 요구하기 때문입니다. 직접 실행할 때는 성공하지만 트리거로 실행했을 때 성공하지 않은 경우가 발생합니다. 이제 도메인에 SSL 인증서가 적용되었으니 트리거로 실행해도 정상적으로 스크립트가 실행될 것입니다.
그런데, 이번 포스트에서 nginx로 웹 서버만 실행했지, 실제로 API를 연결하지는 않았는데요. 이어지는 포스트에서 docker를 사용해서 python 서버를 운영하고, nginx의 proxy_pass로 연결하는 방법을 살펴보겠습니다.
도커(Docker)로 SSL 인증된 API 운영하는 방법 (nginx proxy pass 활용)
참고 사이트
- 부엉이 개발자: Let’s Encrypt의 인증서 발급의 3가지 방법을 소개합니다.