서버 연결 오류

dawoon·2024년 9월 10일

어제까지 문제 없이 작동되던 서버가 "SSH Connection refused(연결 거부)"라는 오류 메세지와 함께 접속이 안되고 추가적인 에러가 발생하여 해당 오류들에 대한 해결 방법에 대해 기록을 남겨보려고 합니다.

1. SSH Connection refused(연결 거부)

(1) Raspberry Pi의 IP 주소 확인

  • 해당 오류는 Raspberry Pi의 IP 주소가 바뀌면서 발생할 가능성이 있는 오류입니다.

    로컬 네트워크 환경에서 Raspberry Pi의 IP 주소는 DHCP 서버에 의해 동적으로 할당되므로 IP 주소가 변경될 수 있습니다.

  • Raspberry Pi에 직접 연결하여 다음 명령어를 통해 IP 주소를 확인

hostname -I

위 명령어를 통해 아래와 같이 IP주소를 확인하였고, 첫번째 IP주소로 SSH 접속을 진행할 수 있었다.

username@servername:~$ hostname -I
100.100.10.29 100.100.10.33 172.17.0.1 172.18.0.1 # 예시
  • 각 IP주소에 대한 설명
    (1) 100.100.10.29 및 100.100.10.33 :
    Raspberry Pi가 로컬 네트워크에서 사용하는 IP 주소입니다.
    이 중 하나가 Wi-Fi, 다른 하나가 유선 연결로 할당된 IP일 가능성이 있습니다.
    (2) 172.17.0.1 및 172.18.0.1 : Docker가 생성한 가상 네트워크 인터페이스에 할당된 IP 주소입니다.
    Docker는 기본적으로 자체 네트워크를 생성하므로, 이 두 개의 IP는 Docker 컨테이너 간의 통신에 사용됩니다.

만약 해결되지 않는 경우 아래의 내용들을 진행해봐도 좋을것 같습니다.

(2) SSH 서비스가 실행 중인지 확인

  • SSH 서비스가 실행되지 않으면 연결이 거부되기 때문에 아래 명령어를 통해 SSH 서버가 제대로 실행되고 있는지 확인합니다.
sudo systemctl status ssh

만약 정상적으로 실행되고 있는 경우 아래와 비슷한 결과값이 나올것입니다.

● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled)
     Active: active (running) since Tue 2024-09-10 10:04:25 KST; 2h 21min ago
TriggeredBy: ● ssh.socket
       Docs: man:sshd(8)
             man:sshd_config(5)
   Main PID: 1524 (sshd)
      Tasks: 1 (limit: 9063)
     Memory: 3.6M (peak: 4.6M)
        CPU: 162ms
     CGroup: /system.slice/ssh.service
             └─1524 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
  • SSH가 실행되고 있지 않다면, 다음 명령어로 SSH 서비스를 시작할 수 있습니다.
sudo systemctl start ssh

(3) 포트 22번이 열려 있는지 확인

  • 방화벽 설정이나 라우터 설정에 따라 포트 22번이 차단될 수 있습니다.
    Raspberry Pi에서 다음 명령어로 포트가 열려 있는지 확인해보세요.
sudo ufw status

비활성화 된 경우 "Status: inactive" 라는 결과값을 확인하실 수 있습니다.

  • 방화벽이 활성화되어 있고 포트 22번이 차단되어 있다면, 다음 명령어로 포트를 열 수 있습니다.
sudo ufw allow 22

(4) IP 충돌 또는 네트워크 문제

  • 네트워크 장비에 문제가 있거나, 동일한 IP 주소를 사용하는 다른 장치가 있을 수 있습니다.
    이 경우 라우터를 재시작하거나 DHCP 설정을 확인하는 것이 좋습니다.

(5) SSH 설정 파일 확인

  • Raspberry Pi의 SSH 설정 파일에서 포트나 기타 설정이 잘못되어 있을 수 있습니다.
    /etc/ssh/sshd_config 파일을 열어 포트가 22번으로 설정되어 있는지 확인해보세요.
sudo nano /etc/ssh/sshd_config

2. 포트 포워딩 오류

SSH 연결 후 Docker로 서버를 열었는데 외부 IP로 접속 시 "연결을 거부"하는 문제가 발생하는 에러가 발생하여 아래와 같은 조치를 진행하였습니다.

(1) 호스트와 Nginx 컨테이너 포트 연결

  • 다음과 같이 명령을 실행하여 호스트와 Nginx 컨테이너 간의 포트를 연결해줍니다.
sudo docker run -d -p 80:80 --name mynginx nginx
  • 위 명령어 실행 후 "bind: address already in use" 라는 내용이 포함된 에러메세지가 발생하였습니다.

(2) 호스트의 80번 포트를 사용하는 프로세스 확인

  • 위 오류 메세지는 다른 프로세스가 이미 해당 포트를 사용하고 있기 때문에 Docker 컨테이너가 80번 포트를 사용할 수 없다는 내용입니다.
    이 문제를 해결하기 위해 다음 명령어로 80번 포트를 사용하는 프로세스를 확인합니다.
sudo lsof -i :80
  • 아래와 같이 출력된 내용 확인 시 Nginx가 80번 포트를 사용 중인 것으로 확인되었습니다.
COMMAND PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   894     root    5u  IPv4  11402      0t0  TCP *:http (LISTEN)
nginx   894     root    6u  IPv6  11403      0t0  TCP *:http (LISTEN)
nginx   895 www-data    5u  IPv4  11402      0t0  TCP *:http (LISTEN)
nginx   895 www-data    6u  IPv6  11403      0t0  TCP *:http (LISTEN)
nginx   896 www-data    5u  IPv4  11402      0t0  TCP *:http (LISTEN)
nginx   896 www-data    6u  IPv6  11403      0t0  TCP *:http (LISTEN)
nginx   897 www-data    5u  IPv4  11402      0t0  TCP *:http (LISTEN)
nginx   897 www-data    6u  IPv6  11403      0t0  TCP *:http (LISTEN)
nginx   898 www-data    5u  IPv4  11402      0t0  TCP *:http (LISTEN)
nginx   898 www-data    6u  IPv6  11403      0t0  TCP *:http (LISTEN)

(3) Nginx 서버 중지

  • Docker 컨테이너가 80번 포트를 사용해야 하고, Nginx를 당장 사용할 필요가 없기 때문에 아래 명령어를 통해 Nginx를 중지시켰습니다.
sudo systemctl stop nginx
  • Nginx가 자동으로 다시 시작되지 않도록 하려면 다음 명령어로 부팅 시 자동 시작을 비활성화할 수 있습니다.
sudo systemctl disable nginx
  • 다시 한번 80번 포트를 사용하는 프로세스를 확인합니다.
sudo lsof -i :80
  • 아무것도 출력되지 않은 경우 중지 명령어가 잘 작동된것 입니다.
    하지만 Docker 컨테이너에 다른 포트 할당하는 명령어 실행 시 오류 메세지가 출력되어 다른 방법을 진행해보았습니다.

    Docker 컨테이너에 다른 포트 할당 명령어

    sudo docker run -d -p 8080:80 --name mynginx nginx

(4) 방화벽 설정 추가

  • 1번 내용과 같이 외부 IP도 변경되었을 가능성이 있다고 판단하여 외부 IP 주소를 먼저 확인하였습다.
curl ifconfig.me

외부 IP 주소는 변경되지 않았음을 확인한 뒤 방화벽을 확인하기 시작했다.

  • Raspberry Pi 자체의 방화벽(UFW)이 외부 접속을 차단하고 있을 가능성이 있어 방화벽 상태를 확인하였습니다.
sudo ufw status

"Status: inactive" 라는 결과 값을 확인하여 방화벽이 비활성화 중인 것을 확인했습니다.

  • 이어서 80번 포트에 방화벽 설정 추가를 진행하였습니다.
sudo ufw allow 80/tcp

설정 후 아래와 같은 결과 값을 통해 규칙이 업데이트 됨을 확인하였습니다.

Rules updated
Rules updated (v6)

다시 "sudo ufw status" 명령어를 통해 방화박 상태를 확인했으나 이전과 동일한 결과 값으로 규칙을 업데이트하여도 방화벽 설정이 비활성화 되고 있는 오류를 확인했습니다.

(5) 방화벽(UFW) 활성화

  • UFW 방화벽을 활성화하여 포트 규칙이 적용되도록 시도합니다.

    sudo ufw enable
  • 위 명령어를 실행하면 UFW 방화벽이 활성화되고, 이미 설정된 규칙이 적용됩니다.
    만약 활성화 도중 UFW가 기존에 허용된 SSH 연결을 차단할까 우려된다면, 다음과 같이 SSH 연결을 허용한 후 UFW를 활성화할 수 있습니다.

sudo ufw allow ssh
sudo ufw enable
  • 방화벽이 활성화된 후 포트 80번이 제대로 허용되었는지 다시 확인합니다.
sudo ufw status

결과값에서 80/tcp와 ssh가 모두 ALLOW로 설정되어 있어야 합니다.

#정상 결과값 예시
Status: active

To                         Action      From
--                         ------      ----
3000/tcp                   ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
22/tcp                     ALLOW       Anywhere
3000/tcp (v6)              ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
22/tcp (v6)                ALLOW       Anywhere (v6)
  • 만약 방화벽이 활성화하려고 해도 다시 비활성화된다면, UFW 서비스에 문제가 있을 수 있습니다.
sudo journalctl -xe

시스템 로그 확인 시 "ufw block" 라고 출력되는 오류 로그를 확인했습니다.

(6) UFW 완전 비활성화 및 iptables 규칙 확인, 초기화

  • UFW가 완전히 비활성화되어 있는지 확인하고, 그럼에도 불구하고 차단 로그가 계속 기록된다면 iptables 규칙을 점검할 필요가 있습니다.
sudo ufw disable
sudo ufw status

UFW 상태가 완전히 "inactive"로 표시되는지 확인하세요.
비활성화 상태임에도 불구하고 UFW BLOCK 로그가 계속 나타난다면 다음 단계로 넘어가세요.

  • UFW가 비활성화되었어도 iptables에 남아 있는 규칙이 여전히 차단을 발생시킬 수 있습니다. 다음 명령어로 iptables 규칙을 확인합니다.
sudo iptables -L

아래와 같은 결과 값이 출력되었고, UFW와 관련된 규칙들과 Docker 관련 규칙도 적용되어 있으며, 특정 트래픽을 허용하고 있는 내용을 확인했습니다.

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ufw-before-logging-input  all  --  anywhere             anywhere
ufw-before-input  all  --  anywhere             anywhere
ufw-after-input  all  --  anywhere             anywhere
ufw-after-logging-input  all  --  anywhere             anywhere
ufw-reject-input  all  --  anywhere             anywhere
ufw-track-input  all  --  anywhere             anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-USER  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ufw-before-logging-forward  all  --  anywhere             anywhere
ufw-before-forward  all  --  anywhere             anywhere
ufw-after-forward  all  --  anywhere             anywhere
ufw-after-logging-forward  all  --  anywhere             anywhere
ufw-reject-forward  all  --  anywhere             anywhere
ufw-track-forward  all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ufw-before-logging-output  all  --  anywhere             anywhere
ufw-before-output  all  --  anywhere             anywhere
ufw-after-output  all  --  anywhere             anywhere
ufw-after-logging-output  all  --  anywhere             anywhere
ufw-reject-output  all  --  anywhere             anywhere
ufw-track-output  all  --  anywhere             anywhere

Chain DOCKER (2 references)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             172.18.0.2           tcp dpt:27017
ACCEPT     tcp  --  anywhere             172.18.0.3           tcp dpt:3000

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination
DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere

Chain DOCKER-ISOLATION-STAGE-2 (2 references)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere

Chain DOCKER-USER (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Chain ufw-after-forward (1 references)
target     prot opt source               destination

Chain ufw-after-input (1 references)
target     prot opt source               destination

Chain ufw-after-logging-forward (1 references)
target     prot opt source               destination

Chain ufw-after-logging-input (1 references)
target     prot opt source               destination

Chain ufw-after-logging-output (1 references)
target     prot opt source               destination

Chain ufw-after-output (1 references)
target     prot opt source               destination

Chain ufw-before-forward (1 references)
target     prot opt source               destination

Chain ufw-before-input (1 references)
target     prot opt source               destination

Chain ufw-before-logging-forward (1 references)
target     prot opt source               destination

Chain ufw-before-logging-input (1 references)
target     prot opt source               destination

Chain ufw-before-logging-output (1 references)
target     prot opt source               destination

Chain ufw-before-output (1 references)
target     prot opt source               destination

Chain ufw-reject-forward (1 references)
target     prot opt source               destination

Chain ufw-reject-input (1 references)
target     prot opt source               destination

Chain ufw-reject-output (1 references)
target     prot opt source               destination

Chain ufw-track-forward (1 references)
target     prot opt source               destination

Chain ufw-track-input (1 references)
target     prot opt source               destination

Chain ufw-track-output (1 references)
target     prot opt source               destination
  • ufw 관련 규칙들이 INPUT, FORWARD, OUTPUT 체인에서 여전히 활성화되어 있습니다.
    UFW가 비활성화 상태로 보이지만, 해당 규칙들이 남아 있어 트래픽을 차단하고 있는 것으로 예상되어 아래 명령어를 통해 ufw-* 규칙들을 제거합니다.
sudo iptables -F
sudo iptables -X

이 명령어는 현재 모든 체인에 있는 규칙을 삭제하고 기본 체인만 남기며, UFW에서 적용한 규칙들도 모두 초기화됩니다.

  • 이후 아래 명령어를 통해 Docker 데몬을 재시작 합니다.
sudo systemctl restart docker
  • 규칙 초기화 후 아래 명령어를 통해 필요한 규칙만 추가합니다.
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -j DROP

이 규칙들은 SSH, HTTP, HTTPS 트래픽만 허용하고 나머지는 차단하는 설정입니다. 필요에 따라 추가적인 포트를 허용할 수 있습니다.

  • 위 설정 적용 후 "sudo journalctl -xe" 명령어로 로그에서 UFW BLOCK 메시지 여부를 재확인 하였고, 로그에 문제 없음을 확인했습니다.

(7) 포트 포워딩 설정 확인

  • 위 설정 적용 후에 서버 접속 시 "ERR_CONNECTION_REFUSED" 에러가 발생하며 서버에서 요청을 거부하고 있는 내용을 확인하였습니다.

  • 이를 해결하기 위해 포트 포워딩 설정부터 확인하기로 결정하여 아래와 같은 순서로 진행하였습니다.

(7-1) 브라우저에서 라우터 관리 페이지 접속

  • 기본 게이트웨이가 "192.168.10.1"인 경우, 브라우저 주소창에 "http://192.168.10.1" 와 같이 입력하여 라우터 관리 페이지에 접속합니다.

    라우터의 IP 주소 확인 방법

    • Windows : 명령 프롬프트(cmd)를 열고, 다음 명령어를 입력합니다.
    	ipconfig

    결과에서 기본 게이트웨이(Default Gateway)로 표시된 IP 주소가 라우터의 내부 IP 주소입니다.

    • Mac 또는 Linux : 터미널을 열고, 다음 명령어를 입력합니다.
     netstat -nr | grep default

    결과에서 default 항목 옆에 있는 IP 주소가 라우터의 내부 IP 주소입니다.

(7-2) 라우터 포트 포워딩 설정

  • ipTIME의 경우
    관리도구 > 고급 설정 > NAT/라우터 관리 > 포트포워드 설정
    으로 들어가서 포트 포워딩을 진행할 수 있습니다.

  • 포트 80을 100.100.10.29 또는 100.100.10.33
    (Raspberry Pi가 로컬 네트워크에서 사용하는 IP 주소)로 포워딩 설정합니다.

  • 외부 포트 : 80
  • 내부 IP 주소 : 100.100.10.29 (또는 100.100.10.33)
  • 내부 포트 : 80
  • 프로토콜 : TCP
  • 규칙 비활성화 : '규칙 비활성화' 체크박스 해제

포트 포워딩 설정 후 외부에서 공용 IP로 다시 접속을 시도해보세요.


이후 정상적으로 외부 서버에 연결되는것을 확인할 수 있었습니다.

profile
코딩 입문

0개의 댓글