어제까지 문제 없이 작동되던 서버가 "SSH Connection refused(연결 거부)"라는 오류 메세지와 함께 접속이 안되고 추가적인 에러가 발생하여 해당 오류들에 대한 해결 방법에 대해 기록을 남겨보려고 합니다.
해당 오류는 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 # 예시
만약 해결되지 않는 경우 아래의 내용들을 진행해봐도 좋을것 같습니다.
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"
sudo systemctl start ssh
sudo ufw status
비활성화 된 경우 "Status: inactive" 라는 결과값을 확인하실 수 있습니다.
sudo ufw allow 22
sudo nano /etc/ssh/sshd_config
SSH 연결 후 Docker로 서버를 열었는데 외부 IP로 접속 시 "연결을 거부"하는 문제가 발생하는 에러가 발생하여 아래와 같은 조치를 진행하였습니다.
sudo docker run -d -p 80:80 --name mynginx nginx
sudo lsof -i :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)
sudo systemctl stop nginx
sudo systemctl disable nginx
sudo lsof -i :80
Docker 컨테이너에 다른 포트 할당 명령어
sudo docker run -d -p 8080:80 --name mynginx nginx
curl ifconfig.me
외부 IP 주소는 변경되지 않았음을 확인한 뒤 방화벽을 확인하기 시작했다.
sudo ufw status
"Status: inactive" 라는 결과 값을 확인하여 방화벽이 비활성화 중인 것을 확인했습니다.
sudo ufw allow 80/tcp
설정 후 아래와 같은 결과 값을 통해 규칙이 업데이트 됨을 확인하였습니다.
Rules updated
Rules updated (v6)
다시 "sudo ufw status" 명령어를 통해 방화박 상태를 확인했으나 이전과 동일한 결과 값으로 규칙을 업데이트하여도 방화벽 설정이 비활성화 되고 있는 오류를 확인했습니다.
UFW 방화벽을 활성화하여 포트 규칙이 적용되도록 시도합니다.
sudo ufw enable
위 명령어를 실행하면 UFW 방화벽이 활성화되고, 이미 설정된 규칙이 적용됩니다.
만약 활성화 도중 UFW가 기존에 허용된 SSH 연결을 차단할까 우려된다면, 다음과 같이 SSH 연결을 허용한 후 UFW를 활성화할 수 있습니다.
sudo ufw allow ssh
sudo ufw enable
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)
sudo journalctl -xe
시스템 로그 확인 시 "ufw block" 라고 출력되는 오류 로그를 확인했습니다.
sudo ufw disable
sudo ufw status
UFW 상태가 완전히 "inactive"로 표시되는지 확인하세요.
비활성화 상태임에도 불구하고 UFW BLOCK 로그가 계속 나타난다면 다음 단계로 넘어가세요.
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
sudo iptables -F
sudo iptables -X
이 명령어는 현재 모든 체인에 있는 규칙을 삭제하고 기본 체인만 남기며, UFW에서 적용한 규칙들도 모두 초기화됩니다.
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 트래픽만 허용하고 나머지는 차단하는 설정입니다. 필요에 따라 추가적인 포트를 허용할 수 있습니다.
위 설정 적용 후에 서버 접속 시 "ERR_CONNECTION_REFUSED" 에러가 발생하며 서버에서 요청을 거부하고 있는 내용을 확인하였습니다.
이를 해결하기 위해 포트 포워딩 설정부터 확인하기로 결정하여 아래와 같은 순서로 진행하였습니다.
라우터의 IP 주소 확인 방법
- Windows : 명령 프롬프트(cmd)를 열고, 다음 명령어를 입력합니다.
ipconfig결과에서 기본 게이트웨이(Default Gateway)로 표시된 IP 주소가 라우터의 내부 IP 주소입니다.
- Mac 또는 Linux : 터미널을 열고, 다음 명령어를 입력합니다.
netstat -nr | grep default결과에서 default 항목 옆에 있는 IP 주소가 라우터의 내부 IP 주소입니다.
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로 다시 접속을 시도해보세요.
이후 정상적으로 외부 서버에 연결되는것을 확인할 수 있었습니다.