리버스 SSH 터널로 NAT 우회하기
중국 인터넷 문제
중국으로 이사하면서 홈 서버와 네트워크가 정상적으로 동작하지 않아, 원인 파악을 하다가 중국은 한국과 다르게 CGNAT이라는 시스템을 사용해서 IPv4 주소를 할당하는 것을 확인했습니다. 중국엔 사람이 너무 많아서 이 방법이 중국 네트워크 구축에 유일한 솔루션이겠지만, 중국 통신사들이 이 방법을 사용하면서 생긴 문제가 홈 네트워크로 직접 연결이 막혀버린다는 점입니다.
다행히도 이 문제에 대한 해결방안이 있는데, 바로 SSH를 통한 포트 포워딩입니다. SSH를 사용해 외부 서버로 연결을 한다면 외부 서버에 접수되는 요청을 SSH를 통해 홈 서버로 포워드하면 됩니다.
이 사용기에서 어떻게 이렇게 외부 서버를 구축하는지, 그리고 어떻게 포워딩 설정을 하는지 설명하겠습니다.
1. DigitalOcean
일단 외부 서버가 필요한데, 저는 이 사용기에서 VPS (Virtual Private Server, 클라우드 서버)를 사용하겠습니다. DigitalOcean이란 사이트에서 VPS를 쉽게 주문할 수 있는데, 사이트에 회원가입을 한 다음, 신용카드 정보를 입력한 후 인스턴스를 하나 생성합니다. 여기에서 크기는 별로 중요하지 않기에 가장 작은 인스턴스를 선택했는데, 한 달에 5달러 정도 청구됩니다.
인스턴스를 생성한 다음 IP 주소를 기억해둡니다. 이 사용기에서 이 IP를 XXX.XXX.XXX.XXX
로 표기하겠습니다.
2. 서버 설정
이제 이 VPS 인스턴스에 ssh
로 연결한 다음, 초기 설정을 해 줍니다. DigitalOcean에서 빠른 시작 가이드가 있는데, 이 가이드를 사용해서 sudo 사용자를 만들고 기타 보안 설정을 해 줍니다. 설정이 완료되면 다음 단계로 넘어갑니다.
/etc/ssh/sshd_config
파일은 수정해서 #GatewayPorts no
를 GatewayPorts yes
로 변경해줍니다. (앞에 있는 해시태그를 삭제한 다음 no
를 yes
로 변경합니다.)
파일을 저장한 다음, sudo service sshd restart
를 사용해서 ssh
서버 서비스를 재시작시킵니다. 이때 연결이 잠시 끊길 수 있는데, 다시 접속하시면 됩니다. 연결이 되었으면 서버를 재부팅합니다.
3. 클라이언트 설정
이제 홈 서버/연결하고 싶은 클라이언트에서 설정을 시작합니다. 예를 들어, 집에 있는 서버의 9000번 포트에 외부 서버의 80번 포트를 연결해보겠습니다. 연결 경로는 다음과 같습니다:
사용자 –> 외부 서버 XXX.XXX.XXX.XXX
(포트 80
) –> 홈 서버 (포트 9000
)
이렇게 연결을 설정하려면 홈 서버에서 다음 SSH 명령을 입력합니다:
ssh -nNT -R 80:localhost:9000 username@XXX.XXX.XXX.XXX
이 명령을 해석해보겠습니다. ssh
는 설명이 필요없고, -nNT
는 SSH 프로그램에게 TTY 인스턴스를 생성하지 말라고 지시합니다 (그래서 이 명령을 실행하면 터미널 프롬프트가 나타나지 않습니다). -R
은 SSH에게 원격 포트 포워드를 요청하고, 그 다음에 오는 부분이 무슨 포트를 어디로 포워드할지 설정해줍니다. 여기서 80
은 외부 서버의 포트고, localhost
는 현재 홈 서버를 가르키며, 9000
은 외부 서버에 도착한 요청을 무슨 포트로 포워드해줄지 알려줍니다. 그 이후의 구문은 (username@XXX.XXX.XXX.XXX
) 그냥 일반적으로 SSH로 서버에 연결할 때 사용되는 인증 정보와 서버 주소입니다.
다른 예시를 들어보자면, 홈 네트워크의 주소 192.168.0.102
에 다른 장치가 있고, 이 장치에서 포트 12984
에 웹 서버가 돌아가고 있다고 가정합니다. 만약 외부 서버의 포트 80
과 443
을 통해 이 장치에 연결하고 싶다면, 홈 서버에서 다음 명령을 실행합니다:
ssh -nNT -R 80:192.168.0.102:12984 username@XXX.XXX.XXX.XXX # HTTP
ssh -nNT -R 443:192.168.0.102:12984 username@XXX.XXX.XXX.XXX # HTTPS
ssh -nNT -R 80:192.168.0.102:12984 -R 443:192.168.0.102:12984 username@XXX.XXX.XXX.XXX # 아니면 한번에 다
연결 경로는 다음 그림과 같습니다:
4. AutoSSH
이제 이 연결을 자동화해주는 서비스를 사용해보겠습니다. 매번 SSH 명령을 실행할 필요없이 포워드를 해주는 서비스 AutoSSH를 설치합니다:
sudo apt install autossh
우분투 서버가 아닌 경우 알맞는 설치 툴로 설치합니다. 다음으로, systemd
설정 파일을 만들어줍니다:
nano /etc/systemd/system/autossh-tunnel.service
다음을 붙여넣기한 다음, 사용 환경에 알맞게 수정해줍니다:
[Unit]
Description=AutoSSH tunnel service
After=network.target
[Service]
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -o "ExitOnForwardFailure yes" -N -R 80:192.168.0.1:80 -R 443:192.168.0.1:443 root@server.example.com -p 22 -i /home/example/.ssh/private-key
[Install]
WantedBy=multi-user.target
이제 systemd
에게 새 설정을 확인하라고 지시한 다음 설정을 활성화해줍니다:
sudo systemctl daemon-reload
sudo systemctl start autossh-tunnel.service
sudo systemctl enable autossh-tunnel.service
만약 SSH 연결도 자동화하고 싶다면, ~/.ssh/config
을 수정하면 됩니다:
Host example-tunnel
HostName server.example.com
User example
Port 22
IdentityFile ~/.ssh/private-key
RemoteForward 80 192.168.0.1:80
RemoteForward 443 192.168.0.1:443
ServerAliveInterval 30
ServerAliveCountMax 3
ExitOnForwardFailure yes
여기에서 RemoteForward
는 별도로 적을 필요가 없는게, AutoSSH가 포워드를 담당하기에 두 번 적는데 큰 의미는 없습니다.
AutoSSH 설정 부분은 이 가이드에서 참고를 많이 했습니다. 만약 추가로 설정하고 싶으신 부분이 있다면 확인해보세요! 원글 작성자에게 감사드립니다.