이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Spring 애플리케이션 장애에서 포트, 방화벽, SSH 문제를 어떻게 구분하는가?
  • connection refused, timeout, 502는 각각 어떤 계층을 의심해야 하는가?
  • 방화벽이나 SSH 설정을 바꿀 때 운영 서버에서 무엇을 조심해야 하는가?

개요

Spring 프로세스가 정상이어도 사용자는 API에 접근하지 못할 수 있다.

서버 안에서 포트를 열지 않았거나, localhost에만 bind했거나, 방화벽이 막았거나, Nginx upstream이 틀렸거나, SSH 접근 경로가 끊겼을 수 있다.

포트와 방화벽 문제는 “서버가 죽었다”가 아니라 “어느 경로에서 연결이 끊겼는가”로 봐야 한다.

요청 경로

단일 서버의 기본 경로는 다음처럼 볼 수 있다.

client
  DNS
    firewall or security group
      Nginx 80/443
        Spring app 127.0.0.1:8080

SSH는 사용자 트래픽 경로가 아니라 운영자가 서버에 들어가는 관리 경로다.

SSH가 된다고 API가 된다는 뜻도 아니고, API가 된다고 SSH가 안전하다는 뜻도 아니다.

포트 확인

서버 안에서 어떤 프로세스가 어떤 주소와 포트에 listen 중인지 확인한다.

ss -ltnp
sudo lsof -iTCP -sTCP:LISTEN -P -n

중요한 차이는 bind 주소다.

127.0.0.1:8080은 서버 내부에서만 접근 가능하다.

0.0.0.0:8080은 외부 interface에서도 접근 가능하다.

Spring app을 직접 외부에 노출할지, Nginx 뒤의 localhost에만 둘지는 운영 설계에 따라 정한다.

대부분은 Nginx나 Load Balancer가 80/443을 받고 Spring은 내부 port에서 받는 구성이 안전하다.

연결 실패 구분

connection refused는 대상 host까지 갔지만 해당 port에서 받는 프로세스가 없을 때 자주 나온다.

curl -v http://127.0.0.1:8080/actuator/health

timeout은 방화벽, security group, routing, 네트워크 경로 문제일 수 있다.

nc -vz api.example.com 443

502 Bad Gateway는 Nginx가 upstream Spring app과 통신하지 못할 때 자주 보인다.

504 Gateway Timeout은 upstream 응답이 timeout 안에 오지 않을 때 의심한다.

같은 사용자 오류라도 원인 계층은 다르다.

Firewall과 Security Group

Linux 서버 안에는 ufw, firewalld, iptables, nftables 같은 방화벽이 있을 수 있다.

클라우드에서는 Security Group, Network ACL, Load Balancer listener도 함께 본다.

sudo ufw status verbose
sudo firewall-cmd --list-all
sudo iptables -S

운영에서 방화벽을 바꿀 때 가장 위험한 것은 SSH를 스스로 끊는 것이다.

방화벽 변경 전에는 현재 SSH 세션을 유지하고, 별도 터미널에서 새 접속이 되는지 확인하며, rollback 명령을 준비한다.

SSH 기본

SSH는 운영 서버 접근의 마지막 통로일 수 있다.

기본적으로 password login보다 key 기반 접근을 사용하고, 개인 계정과 감사 가능한 sudo 정책을 둔다.

ssh app-admin@server.example.com
who
last -a | head
sudo -l

공유 계정 하나로 모두 접속하면 장애 중 누가 어떤 명령을 실행했는지 추적하기 어렵다.

SSH key 교체, 퇴사자 권한 제거, bastion host 사용 여부는 운영 보안과 직접 연결된다.

Nginx와 Spring Port

Nginx upstream과 Spring port가 맞는지 확인한다.

upstream order_api {
    server 127.0.0.1:8080;
}
 
server {
    listen 443 ssl;
 
    location / {
        proxy_pass http://order_api;
    }
}

Spring 설정도 함께 봐야 한다.

server.port=8080
management.server.port=8081

Nginx가 8080을 바라보는데 Spring이 8081로 떠 있으면 Nginx 502가 난다.

management port를 분리했다면 health check 대상 port도 함께 맞춰야 한다.

운영 체크리스트

  • Spring app이 의도한 address와 port에 listen 중인가?
  • Nginx upstream port와 Spring server.port가 일치하는가?
  • 외부에는 80/443만 열고 내부 app port는 막는가?
  • cloud security group과 OS firewall 규칙이 충돌하지 않는가?
  • SSH 접근은 key 기반이고 개인별 추적이 가능한가?
  • firewall 변경 전 rollback 방법과 유지 중인 SSH 세션이 있는가?

장애 신호

  • 서버 내부 curl 127.0.0.1:8080은 실패하지만 systemctl status는 active다.
  • 서버 내부 health는 성공하지만 외부에서는 timeout이 난다.
  • Nginx access log에는 502가 늘고 Spring access log에는 요청이 없다.
  • 8080 port를 다른 프로세스가 이미 사용 중이다.
  • 방화벽 변경 직후 SSH 새 접속이 실패한다.
  • health check가 management port가 아니라 사용자 API port를 잘못 보고 있다.

안전한 완화 조치

포트 문제에서는 먼저 내부에서부터 바깥으로 확인한다.

  1. Spring process가 떠 있는지 본다.
  2. ss -ltnp로 listen port를 본다.
  3. 서버 내부에서 curl로 health를 확인한다.
  4. Nginx에서 upstream 연결을 확인한다.
  5. OS firewall과 cloud security group을 본다.
  6. 외부 client에서 다시 확인한다.

방화벽 변경은 작은 단위로 하고 즉시 새 SSH 접속을 시험한다.

외부에 Spring port를 급하게 직접 열기보다 Nginx/LB 경로를 복구하는 편이 일반적으로 안전하다.

인프라 담당자와 공유할 자료

증상: 외부 사용자는 502, 서버 내부 health는 성공
서비스: order-api prod
Spring port: 8080, listen 127.0.0.1
Nginx upstream: 127.0.0.1:8081로 설정되어 있음
로그: Nginx error log connect() failed
요청: upstream 설정 변경 승인과 reload 영향 확인

포트 문제는 명령 출력과 설정 값을 함께 줘야 빠르게 해결된다.

실전 팁

  • connection refusedtimeout을 구분한다.
  • 서버 내부 확인과 외부 확인을 따로 기록한다.
  • Nginx access log, error log, Spring log를 같은 시간대로 본다.
  • SSH와 사용자 트래픽 경로를 혼동하지 않는다.
  • 방화벽 변경 전에는 항상 현재 접속 유지와 rollback을 준비한다.

위험 신호!

  • 운영 중 SSH port를 바꾸면서 새 접속 시험을 하지 않는다.
  • Spring app port를 외부에 직접 열어둔다.
  • Nginx 502를 애플리케이션 500과 같은 것으로 취급한다.
  • OS firewall과 cloud security group 중 어디서 막히는지 모른다.
  • port 충돌을 해결하려고 임의 프로세스를 바로 kill한다.

확인 질문

확인 질문

  • connection refusedtimeout의 차이는 무엇인가?
    • connection refused는 보통 대상 port에 listen 프로세스가 없다는 신호이고, timeout은 방화벽이나 네트워크 경로에서 응답이 오지 않는 신호일 수 있다.
  • Nginx 502에서 먼저 확인할 것은 무엇인가?
    • Nginx upstream 주소와 port, Spring listen port, Nginx error log, Spring access log에 요청이 도달했는지 여부다.
  • 방화벽 변경에서 가장 조심할 점은 무엇인가?
    • SSH 접근을 스스로 차단하지 않도록 기존 세션을 유지하고 새 접속 시험과 rollback 명령을 준비하는 것이다.

참고 문서