[Server] Nginx로 안전한 서버 구축하기(실습편)

gogori6565·2026년 2월 6일

Server / DevOps

목록 보기
5/5
post-thumbnail

드디어 실습편! 역시 중요한 건 실제 적용이겠죠.
더도말고 덜도말고 바로 시작!


1단계. 명령어 수행 위치: 서버 접속 (SSH)

모든 명령어(sudo apt install, sudo certbot 등)는 원격으로 접속한 리눅스 서버의 터미널 환경에서 수행한다.

1. 어디서 (장소)

  • PC (로컬): 나의 개인 컴퓨터
  • 서버 (원격): 실제로 서비스가 구동될 백엔드 서버 (클라우드 인스턴스, VPS 등)

2. 어떻게 (방법)
내 PC에서 SSH(Secure Shell)라는 프로토콜을 이용해 원격 서버에 접속해야 함

(1) SSH 클라이언트 실행:

  • Windows: PuTTY, MobaXterm, 또는 Git Bash, Windows Terminal (PowerShell/CMD)에서 기본 SSH 명령어 사용
  • macOS/Linux: 기본 터미널 앱에서 바로 SSH 명령어 사용

-> 나는 Git Bash 가 개인적으로 편해서 Git Bash로!

(2) 접속 명령어

ssh [사용자이름]@[서버 IP 주소 또는 도메인]
# 예: ssh ubuntu@10.0.0.5
  • Permission denied (publickey) 접속 오류 발생 시
    • 서버가 사용자 신원을 확인하는 과정에서 인증에 실패했음을 의미
    • 특히, 서버가 공개 키(Public Key)를 이용한 인증 방식(Key-based Authentication)을 요구했는데, 클라이언트(내 PC)가 유효한 개인 키(Private Key)를 서버에 제시하지 못했거나 서버가 그 키를 수락하지 않았을 때 발생
# 올바른 개인 키 파일 경로를 지정해야 함
ssh -i /path/to/your/private_key_file [사용자이름]@[서버 IP 주소]

2단계. 방화벽 포트 열기

(1) iptables 리스트 확인

sudo iptables -L INPUT -n --line-numbers
  • 결과 해석: ACCEPT라고 되어 있는 줄의 dpt:80, dpt:443 등이 보여야 함
  • LISTEN 상태라는 것은 해당 포트가 "열려 있고, 외부의 연결 요청을 받을 준비가 되었다"는 뜻
  • 만약 맨 아래쪽에 REJECTDROP 규칙이 있다면, 그보다 위쪽에 허용 규칙이 있어야 포트가 열린다. (중요)

(2) 포트 열기 명령어

# INPUT 체인의 [번호] 위치에 80번 포트(tcp)를 허용(ACCEPT)하는 규칙을 삽입

sudo iptables -I INPUT [번호] -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT [번호] -p tcp --dport 443 -j ACCEPT

(3) 포트를 허용했다면, 설정을 저장하도록 하자.

# 설정 저장 (재부팅 후에도 유지되도록)
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

3단계. Nginx 및 Certbot 설치

1. Nginx 설치

  • sudo apt install -y nginx

2. Let’s Encrypt 인증서 발급 certbot 설치

  • sudo apt install -y certbot
  • sudo apt install -y python3-certbot-nginx

3. 도메인 인증서 발급 시작

  • sudo certbot certonly --nginx
  • 이메일 입력 후 Y 누르다가 domain 을 입력하라고 뜨면 생성한 도메인 주소를 입력 → 이메일 주소 아무거나(abc@abc.com)
  • 주의 - 서버의 80, 443포트가 오픈되어있지 않으면 인증서 발급 실패
  • 주의 - 도메인 IP 주소에 서버 IP 주소 입력 필요
  • (재발급 시) sudo certbot --nginx -d [도메인명]

4. 발급된 인증서 및 리버스프록시 설정

  • (a) Nginx 기본 conf 파일 삭제
    • sudo rm /etc/nginx/sites-available/default
    • sudo rm /etc/nginx/sites-enabled/default
  • (b) conf 파일 생성 및 등록
    • sudo vi /etc/nginx/sites-available/(원하는이름).conf → (이름: server 추천)

Redirect HTTP to HTTPS (80 포트)

server {
    listen 80;                          # HTTP (80포트)로 들어오는 요청을 받음
    server_name (발급한 도메인);        # moongeul.kro.kr 도메인에 대해서만 적용
    
    location / {                        # 모든 경로(/)에 대해
        return 301 https://$host$request_uri;  # HTTPS로 영구 리다이렉트
    }
}
  • $host$request_uriNginx 변수입니다. Nginx가 자동으로 값을 채워줍니다.
    • $hostmoongeul.kro.kr (자동으로 채워짐)
    • $request_uri/board/post?id=123 (자동으로 채워짐)

HTTPS server (443 포트)

server {
	listen 443 ssl;
	server_name (발급한 도메인); # Change this to your domain

	ssl_certificate /etc/letsencrypt/live/(발급한 도메인)/fullchain.pem; # managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/(발급한 도메인)/privkey.pem; # managed by Certbot

	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

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

✨전체 동작 흐름

1. 사용자: http://moongeul.kro.kr/page 접속
   ↓
2. Nginx (80포트): "HTTPS로 가세요!"301 리다이렉트
   ↓
3. 사용자: https://moongeul.kro.kr/page 재접속
   ↓
4. Nginx (443포트): SSL 암호화 + 인증서 확인
   ↓
5. Nginx: localhost:8080으로 요청 전달 (프록시)6. 실제 애플리케이션(8080): 요청 처리 후 응답
   ↓
7. Nginx: 응답을 받아서 사용자에게 전달

요구사항 체크

  • 80 포트: HTTP 접속 시 HTTPS로 리다이렉트
  • 443 포트: HTTPS로 암호화된 연결 제공
  • SSL 인증서: Let's Encrypt로 보안 연결
  • 리버스 프록시: 실제 앱(8080)을 외부에 노출하지 않고 안전하게 연결

*아무튼 위 내용(코드)들 기입 후 저장

5. 심볼릭 설정으로 conf 파일 활성화
(심볼릭 링크로 enabled 경로에도 conf 파일 연결)

  • sudo ln -s /etc/nginx/sites-available/(생성한 설정 파일 이름).conf /etc/nginx/sites-enabled/(생성한 설정 파일 이름).conf

6. Nginx 재시작

  • sudo systemctl restart nginx


추가 단계. Nginx 버전 숨기기

위 설정을 모두 완료하고 내 도메인 주소로 들어가면

502 Bad Gateway
nginx/[버전] (Ubuntu)

이런 식의 문구가 뜨는 걸 볼 수 있다.
502가 떴다는 건 Nginx가 잘 돌아가고 있다는 것! 현재 스프링 서버가 안 켜져 있어서 502가 뜨는 것이다.
하지만, nginx 뒤에 버전이 뜨는 건 웬만하면 지워주는 게 좋다.

Nginx 의 버전을 알 수 있다면, 공격 포인트가 될 수 있다. 해당 버전에서 어떤 보안 취약점이 있었는지 확인하고 그 부분을 통해 해킹에 노출되기 때문에 버전을 숨겨주면 더 안전한 운영을 할 수 있다.

Nginx의 버전 노출 여부 확인
nginx 서버 응답 헤더값을 보면 알 수 있다.

curl -IsL [확인하고자 하는 사이트 URL] --insecure

Nginx의 버전 숨기는 법

# 서버의 default.conf 파일에서 server_tokens 값 off로 수정
sudo vi /etc/nginx/nginx.conf

# 주석으로 꺼져 있는 것을 주석 없애서 켜기
http{
         server_tokens off;
}

# 설정 변경 후 서비스 재시작 필요
sudo nginx -s reload
sudo systemctl restart nginx

Response Header에 "Server: Nginx"까지 전부 숨기는 법
서버의 버전을 넘어 서버의 종류까지 숨기는 법

# nginx-extras
sudo apt-get install nginx-extras

# /etc/nginx/nginx.conf 파일 수정
http {
...
	more_set_headers "Server:"; // 새로 만듦 (server 아래에 만듦)
...
}
# 설정 변경 후 서비스 재시작 필요
sudo nginx -s reload
sudo systemctl restart nginx

profile
나대로 열심히 하다보면 또 어딘가에 닿아있겠지 p(´∇`)q

0개의 댓글