SSL 인증서 관련 트러블 슈팅 : nginx: [emerg] cannot load certificate

조대훈·2024년 11월 1일
post-thumbnail

nginx Restarting..

docker logs 확인 결과 nginx 가 계속 해서 재부팅 되고 있음을 확인

docker logs nginx 로그를 확인 해보자

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: IPv6 listen already enabled
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/11/01 02:25:38 [emerg] 1#1: cannot load certificate "/etc/letsencrypt/live/api.togerun.shop/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/letsencrypt/live/api.togerun.shop/fullchain.pem, r) error:10000080:BIO routines::no such file)
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/api.togerun.shop/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/letsencrypt/live/api.togerun.shop/fullchain.pem, r) error:10000080:BIO routines::no such file)

해당 경로에 SSL 인증서를 찾을 수 없다는 메세지 확인.

nginx.conf 인증서 설정 부분

ssl_certificate /etc/letsencrypt/live/api.togerun.shop/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.togerun.shop/privkey.pem;

docekr-compose.yml 마운트 부분

volumes:
  - ./nginx.conf:/etc/nginx/nginx.conf:ro
  - ./ssl:/etc/nginx/ssl:ro
  - ./certbot/conf:/etc/letsencrypt:ro
  - ./certbot/www:/var/www/certbot:ro

전부 알맞게 마운트 되어 있었다. 왜 못찾는 것이지..?

로컬 서버(ec2)에서 인증서 파일 위치 확인
ls -l /home/ubuntu/app/certbot/conf/live/api.togerun.shop/

ubuntu@ip-172-31-33-33:~$ ls -l /home/ubuntu/app/certbot/conf/live/api.togerun.shop/ ls: cannot access '/home/ubuntu/app/certbot/conf/live/api.togerun.shop/': No such file or directory

파일이 왜 없지.. 분명 인증서를 받았는데..?
기억을 잘 더듬어 보니 cerbot 이 아니라 lets encrypt 로 직접 발급 받은 기억이 있다..
어쩐지 2번째 발급 받을 때엔 과정이 조금 다르더라..
lestsencrypt 폴더에서 찾아보자

sudo ls -l /etc/letsencrypt/live/api.togerun.shop/

-rw-r--r-- 1 root root 692 Oct 31 18:16 README
lrwxrwxrwx 1 root root  40 Oct 31 18:16 cert.pem -> ../../archive/api.togerun.shop/cert1.pem
lrwxrwxrwx 1 root root  41 Oct 31 18:16 chain.pem -> ../../archive/api.togerun.shop/chain1.pem
lrwxrwxrwx 1 root root  45 Oct 31 18:16 fullchain.pem -> ../../archive/api.togerun.shop/fullchain1.pem
lrwxrwxrwx 1 root root  43 Oct 31 18:16 privkey.pem -> ../../archive/api.togerun.shop/privkey1.pem

1.파일이 있음을 확인 cerbot 폴더를 생성 후 -> 권한 설정 -> 옮길 것인지
2.간단하게 docker-compose.yml 파일에서 마운트 하는 부분만 바꿔줄 것인지 결정.
추후에 cerbot 으로 자동갱신 할것도 염려해서 1안을 택했다.

# Let's Encrypt 디렉토리 구조 확인
sudo ls -la /etc/letsencrypt/live/
sudo ls -la /etc/letsencrypt/archive/

# 심볼릭 링크 확인
sudo readlink -f /etc/letsencrypt/live/api.togerun.shop/fullchain.pem
sudo readlink -f /etc/letsencrypt/live/api.togerun.shop/privkey.pem

# 실제 인증서 파일 찾기
sudo find /etc/letsencrypt -name "fullchain*.pem"
sudo find /etc/letsencrypt -name "privkey*.pem"

# 1. certbot 디렉토리 구조 생성
sudo mkdir -p /home/ubuntu/app/certbot/conf/live/api.togerun.shop
sudo mkdir -p /home/ubuntu/app/certbot/conf/archive/api.togerun.shop

# 2. archive 디렉토리의 인증서 복사
sudo cp /etc/letsencrypt/archive/api.togerun.shop/fullchain1.pem /home/ubuntu/app/certbot/conf/archive/api.togerun.shop/
sudo cp /etc/letsencrypt/archive/api.togerun.shop/privkey1.pem /home/ubuntu/app/certbot/conf/archive/api.togerun.shop/

# 3. live 디렉토리에 심볼릭 링크 생성
cd /home/ubuntu/app/certbot/conf/live/api.togerun.shop
sudo ln -s ../../archive/api.togerun.shop/fullchain1.pem fullchain.pem
sudo ln -s ../../archive/api.togerun.shop/privkey1.pem privkey.pem

# 4. 권한 설정
sudo chown -R ubuntu:ubuntu /home/ubuntu/app/certbot
sudo chmod -R 755 /home/ubuntu/app/certbot/conf
sudo chmod 700 /home/ubuntu/app/certbot/conf/live
sudo chmod 700 /home/ubuntu/app/certbot/conf/archive
sudo chmod 600 /home/ubuntu/app/certbot/conf/archive/api.togerun.shop/*.pem

# 5. 복사된 파일 확인
ls -la /home/ubuntu/app/certbot/conf/live/api.togerun.shop/
ls -la /home/ubuntu/app/certbot/conf/archive/api.togerun.shop/

2안으로 변경시에 아래 처럼 수정하기만 하면 된다.

services:
  nginx:
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro  # 이 부분을 수정
      - ./certbot/www:/var/www/certbot:ro
# 컨테이너 재시작
docker-compose down
docker-compose up -d

nginx.conf

ssl_certificate /etc/letsencrypt/live/api.togerun.shop/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.togerun.shop/privkey.pem;

docker-compose.yml
conf 와 yml을 재차 확인 해준다.

volumes:
  - ./nginx.conf:/etc/nginx/nginx.conf:ro
  - ./ssl:/etc/nginx/ssl:ro
  - ./certbot/conf:/etc/letsencrypt:ro
  - ./certbot/www:/var/www/certbot:ro

ubuntu@ip:~/app$ docker ps
컨테이너 상태를 확인 해보자.

CONTAINER ID   IMAGE                   COMMAND                  CREATED             STATUS                         PORTS                                                                      NAMES
e531da193b82   chohune/spring:latest   "java -jar /app.jar"     About an hour ago   Up About an hour (unhealthy)   8080/tcp                                                                   spring-boot-green
028c04971573   certbot/certbot         "/bin/sh -c 'trap ex…"   12 hours ago        Up 12 hours                    80/tcp, 443/tcp                                                            certbot
97144b66e40a   454f43153389            "java -jar /app.jar"     12 hours ago        Up 12 hours (unhealthy)        8080/tcp                                                                   spring-boot-blue
0b2fbf9f03ab   redis:alpine            "docker-entrypoint.s…"   12 hours ago        Up 12 hours                    6379/tcp                                                                   redis_boot
3bd05e94c813   nginx:alpine            "/docker-entrypoint.…"   12 hours ago        Up 2 minutes                   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   nginx

ubuntu@ip:~/app$ curl -v http://localhost:80
80포트로 요청을 보내보자.

* Host localhost:80 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:80...
* Connected to localhost (::1) port 80
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.27.2
< Date: Fri, 01 Nov 2024 03:36:19 GMT
< Content-Type: text/html
< Content-Length: 169
< Connection: keep-alive
< Location: https://localhost/
< 
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.27.2</center>
</body>
</html>
* Connection #0 to host localhost left intact

ubuntu@ip:~/app$ curl -v https://api.togerun.shop
좀 더 자세한 health 체크를 위해 curl -v 로 api endpoint 로 요청을 보내본다.

* Host api.togerun.shop:443 was resolved.
* IPv6: (none)
* IPv4: 
*   Trying 
* Connected to api.togerun.shop (43.203.60.237) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=api.togerun.shop
*  start date: Oct 31 08:17:51 2024 GMT
*  expire date: Jan 29 08:17:50 2025 GMT
*  subjectAltName: host "api.togerun.shop" matched cert's "api.togerun.shop"
*  issuer: C=US; O=Let's Encrypt; CN=E5
*  SSL certificate verify ok.
*   Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
*   Certificate level 1: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://api.togerun.shop/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: api.togerun.shop]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.5.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: api.togerun.shop
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/2 302 
< server: nginx/1.27.2
< date: Fri, 01 Nov 2024 03:37:03 GMT
< content-length: 0
< vary: Origin
< vary: Access-Control-Request-Method
< vary: Access-Control-Request-Headers
< x-content-type-options: nosniff
< x-xss-protection: 0
< cache-control: no-cache, no-store, max-age=0, must-revalidate
< pragma: no-cache
< expires: 0
< x-frame-options: DENY
< location: http://api.togerun.shop/api/member/login
< strict-transport-security: max-age=31536000; includeSubDomains
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< access-control-allow-credentials: true
< access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE
< access-control-allow-headers: Authorization, Cache-Control, Content-Type, Accept, Last-Event-ID
< 
* Connection #0 to host api.togerun.shop left intact
  1. HTTP → HTTPS 리다이렉션이 정상 작동 중. (301 Moved Permanently)
  2. HTTPS 연결이 정상적으로 작동 중.
    • SSL 인증서가 올바르게 인식됨
    • TLSv1.3이 사용됨
    • 인증서가 api.togerun.shop에 대해 유효함
  3. 애플리케이션 응답 정상.
    • 302 리다이렉션이 발생 (로그인 페이지로)
    • CORS 헤더가 제대로 설정됨
    • 보안 헤더들이 올바르게 설정됨

본인이 cerbot 으로 인증서를 받았는지, Lets encrypt 로 직접 받았는지 분명하게 상기 해두자..

profile
백엔드 개발자를 꿈꾸고 있습니다.

0개의 댓글