Spring

[Spring] 로컬 및 운영 환경에서 HTTPS 적용하기

빈 🐥 2025. 5. 29. 02:33
반응형

표지

웹 서비스를 운영할 때 HTTPS(SSL) 적용은 보안의 기본입니다. 따라서 이번 글에서는 개발 환경(로컬)과 운영 환경에서 HTTPS를 적용하는 방법을 정리하려고 합니다.

  • 로컬에서는 Self-Signed 인증서를 사용하고,
  • 운영 환경에서는 Let's Encrypt + Nginx를 통한 무료 SSL 인증서 적용했습니다.
  • 마지막에는 오류 사례와 해결 방법까지 정리해보았습니다.

 

1. 로컬에서 HTTPS 적용 방법 (Self-Signed 인증서)

1-1. Self-Signed 인증서 생성 (Java Keytool 사용)

로컬에서 테스트용 HTTPS를 적용하려면 자체 서명(Self-Signed) 인증서를 생성해야 합니다.

아래 명령어 실행

keytool -genkeypair -alias local-ssl -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650

 

  • 생성 시 다음 정보 입력
    • 비밀번호
    • 이름 / 조직 / 지역 : 대략적으로 입력
    • keystore.p12 파일이 생성됨

 

입력 예시

Enter keystore password:
  (예: password12345!)

Re-enter new password:
  (예: password12345!

What is your first and last name?
  [Unknown]: localhost

What is the name of your organizational unit?
  [Unknown]: Dev Team

What is the name of your organization?
  [Unknown]: Project Name

What is the name of your City or Locality?
  [Unknown]: Seoul

What is the name of your State or Province?
  [Unknown]: Seoul

What is the two-letter country code for this unit?
  [Unknown]: KR

Is CN=localhost, OU=Dev Team, O=HisCool, L=Seoul, ST=Seoul, C=KR correct?
  [no]: yes

 

 

각 항목 설명

first and last name localhost 테스트용, 로컬 개발 시 localhost 추천 (CN = Common Name)
organizational unit Dev Team 부서명, 자유 입력
organization HisCool 프로젝트명, 회사명
City or Locality Seoul 도시 이름
State or Province Seoul 주/도 이름
country code KR 국가 코드 (대한민국 = KR)

이 과정을 마치면 `keystore.p12` 파일이 생성됩니다.

 

1-2. Spring Boot `application.yml` 설정

application.yml에 다음과 같이 작성:

server:
  port: 8443
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: password
    key-store-type: PKCS12

 

 

1-3. 접속 테스트

  • 서버를 실행한 후 https://localhost:8443 에 접속해보세요.
  • 브라우저에서 보안 경고가 발생하는데, 이는 Self-Signed 인증이므로 정상

 

2. 운영 환경에서 HTTPS 적용 방법 (Let's Encrypt)

Let's Encrypt + Nginx 활용

 

운영 서버에서는 Self-Signed 대신 Let's Encrypt를 사용하는 것이 일반적입니다.
도메인을 준비하고, Nginx와 Certbot을 활용해 무료 SSL 인증서를 발급받는 방법을 알아봅니다.

 

2-1. 도메인 준비

  • 도메인은 가비아카페24, AWS Route53 등에서 구매
    • 저는 가비아에서 구매하였습니다
  • DNS 설정에서 서버의 퍼블릭 IP와 연결

 

2-2. Nginx 설치

sudo apt update
sudo apt install nginx

 

 

2-3. Certbot 설치 및 인증서 발급

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

 

 

Let's Encrypt 인증서 발급 시 필수 정보 중 하나인 이메일 주소를 입력해야 합니다.

만약 인증서 갱신이나 보안 경고가 발생하면 해당 이메일로 알림이 온다고 합니다.

Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): ( 예 : gmail@gmail.com )

 

이후 약관 동의를 물어보는데

  • "동의하시겠습니까?" 하면 Y 입력하면 됩니다.
  • "이메일 공유 동의" 여부도 물어볼 수 있는데, 이건 선택 사항이라 N을 입력해도 상관없습니다.
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must
agree in order to register with the ACME server. Do you agree to the Terms of
Service? (Y)es/(N)o: Y

Would you be willing 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: N

 

 

2-4. Nginx 설정 (/etc/nginx/sites-available/default 수정)

보통 Nginx 설정은 다음 디렉토리에 있음

/etc/nginx/sites-available/

 

 

default 파일을 수정

server {
    listen 80;
    server_name domain.com www.domain.com;

    # Let's Encrypt 인증서 발급용 (HTTP-01 챌린지)
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name domain.com www.domain.com;

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

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

 

 

2-5. Nginx 테스트 후 적용

설정 오류 확인:

sudo nginx -t

 

다음과 같이 나오면 성공입니다.

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

 

Nginx 재시작

sudo systemctl restart nginx

 

 

2-6. Spring Boot 설정

  • 운영 환경에서는 Nginx가 SSL 처리를 담당
  • Spring Boot는 HTTP (8080 포트) 로만 실행
  • application.yml의 SSL 설정은 필요 없습니다.

 

2-7. 접속 확인

  • `https://domain.com` 접속 
  • `https://www.domain.com` 접속

 

 

2-8. DNS 반영 지연 주의

가비아, AWS Route53 등에서 DNS 설정 후 적용까지 최대 30분~1시간 소요될 수 있습니다.

저는 1시간 정도 걸려서 설정을 잘못했나 걱정했습니다..

설정 방법은 다음 블로그에서 소개드릴 예정입니다!

 

 

3. 비고) IP만으로 HTTPS 적용 가능할까?

3-1. Self-Signed 인증서 + Spring Boot

  • 도메인 없이 IP 주소를 대상으로 HTTPS를 적용하고 싶다면, Self-Signed 인증서를 생성해서 Spring Boot에서 직접 SSL을 적용할 수 있습니다.
  • 다만, 브라우저에서 보안 경고가 계속 발생하고, 실제 운영 서비스에서는 사용자 신뢰성 확보 불가.
  • 보안 테스트, 내부망 용도로만 적합.

 

3-2. 적용 절차 (IP 용 HTTPS)

GPT가 알려준 절차는 다음과 같았지만, 시도해보지는 않음

 

3-2-1. Selft-Signed 인증서 생성 (IP 용)

IP는 CN (Common Name)으로 넣어서 인증서 생성

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout selfsigned.key \
    -out selfsigned.crt \
    -subj "/C=KR/ST=Seoul/L=Seoul/O=Test/OU=Dev/CN=YOUR.SERVER.IP.ADDRESS"

 

 

3-2-2. PKCS12 키스토어로 변환

openssl pkcs12 -export -in selfsigned.crt -inkey selfsigned.key -out keystore.p12 -name selfsigned

 

3-2-3. Spring Boot에 적용

`application.yml`

server:
  port: 8443
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: [비밀번호]
    key-store-type: PKCS12

 

 

3-2-4. 접속 테스트

  • `https://[서버IP]:8443` 접속 (브라우저 경고 발생 예상)

 

3-3. 도메인 없이 공인 인증서 발급 → 불가능

  • Let's Encrypt, 일반 CA(인증기관)는 IP 주소로는 SSL 인증서를 발급해주지 않아.
  • 공인된 SSL 인증서는 도메인 필수.
  • 따라서 가비아에서 500원짜리 도메인을 구입하여 진행함

 

GPT's의 추천

  • 테스트/내부망 ➔ Self-Signed 인증서 + Spring Boot 적용 OK
  • 운영 서비스 ➔ 도메인 확보 후 Let's Encrypt 추천
  • 브라우저 신뢰 필요 ➔ 도메인 없이 불가능 (보안 경고 피할 수 없음)

 

4. 마무한 오류들 정리

4-1. certbot: error: unrecognized arguments: —nginx

certbot: error: unrecognized arguments: —nginx

 

원인

`--nginx` 옵션 앞에 있는 하이픈(-)이 잘못 입력됨

 

해결 방법

--nginx 옵션 앞의 하이픈은 -- (ASCII 하이픈 두 개) 를 사용해야 함

 

4-2. "default" E212: Can't open file for writing

원인

이 오류는 파일을 수정하려고 했는데, 권한이 부족해서 저장이 안 되는 경우에 발생.
즉, /etc/nginx/sites-available/default 파일을 루트 권한 없이 열어서 저장하려 했기 때문에 발생/

 

해결 방법

`sudo`로 열어서 수정

Nginx 설정 파일은 시스템 설정 파일이기 때문에 sudo 권한이 필요

파일을 수정할 때 아래 명령어로 실행

sudo nano /etc/nginx/sites-available/default

 

위 명령어로 열어서 수정하고, 저장 (Ctrl + O), 종료 (Ctrl + X) 

 

4-3. [emerg] duplicate listen [::]:443

원인

  • listen [::]:443 설정이 중복되어 있다는 의미야.
  • 즉, 동일한 포트(443)에 대해 두 번 이상 listen 지시어를 선언한 상태

 

해결 방법

중복된 `listen` 지시어 제거

  • `default` 파일 안에서 listen 부분을 확인하고 
  • 중복된 부분을 하나로 통합

 

4-4. duplicate location "/" in ~ (위와 거의 비슷)

원인

기존 정적 파일용 location /을 삭제하지 않음

location / {
    try_files $uri $uri/ =404;
}

 

해결 방법

기존 정적 파일용 location / 를 제거하면 됨

 

5. 마무리

로컬 개발 환경에서의 Self-Signed 인증서 적용부터, 운영 환경에서의 Let's Encrypt와 Nginx를 활용한 무료 SSL 인증서 발급 및 적용까지—이번 글에서는 HTTPS 적용의 전 과정을 살펴보았습니다.

 

요약하자면:

  • 개발 환경에서는 Self-Signed 인증서를 통해 빠르게 HTTPS 테스트를 해볼 수 있으며,
  • 운영 환경에서는 반드시 도메인을 확보한 후, Let's Encrypt로 무료이자 공인된 SSL 인증서를 발급받아 적용해야 합니다.

이번 글이 SSL 인증서 적용을 망설이는 분들께 실제 적용 방법과 시행착오를 줄일 수 있는 경험담으로 도움이 되길 바랍니다.

반응형