리버스 SSH 터널로 NAT 우회하기

!
경고: 이 글이 작성된 지 365일이 넘었습니다. 글의 정보가 오래되어 부정확할 수 있습니다.

중국 인터넷 문제

중국으로 이사하면서 홈 서버와 네트워크가 정상적으로 동작하지 않아, 원인 파악을 하다가 중국은 한국과 다르게 CGNAT이라는 시스템을 사용해서 IPv4 주소를 할당하는 것을 확인했습니다. 중국엔 사람이 너무 많아서 이 방법이 중국 네트워크 구축에 유일한 솔루션이겠지만, 중국 통신사들이 이 방법을 사용하면서 생긴 문제가 홈 네트워크로 직접 연결이 막혀버린다는 점입니다.

nat-1

다행히도 이 문제에 대한 해결방안이 있는데, 바로 SSH를 통한 포트 포워딩입니다. SSH를 사용해 외부 서버로 연결을 한다면 외부 서버에 접수되는 요청을 SSH를 통해 홈 서버로 포워드하면 됩니다.

이 사용기에서 어떻게 이렇게 외부 서버를 구축하는지, 그리고 어떻게 포워딩 설정을 하는지 설명하겠습니다.

1. DigitalOcean

일단 외부 서버가 필요한데, 저는 이 사용기에서 VPS (Virtual Private Server, 클라우드 서버)를 사용하겠습니다. DigitalOcean이란 사이트에서 VPS를 쉽게 주문할 수 있는데, 사이트에 회원가입을 한 다음, 신용카드 정보를 입력한 후 인스턴스를 하나 생성합니다. 여기에서 크기는 별로 중요하지 않기에 가장 작은 인스턴스를 선택했는데, 한 달에 5달러 정도 청구됩니다.

인스턴스를 생성한 다음 IP 주소를 기억해둡니다. 이 사용기에서 이 IP를 XXX.XXX.XXX.XXX로 표기하겠습니다.

nat-2

2. 서버 설정

이제 이 VPS 인스턴스에 ssh로 연결한 다음, 초기 설정을 해 줍니다. DigitalOcean에서 빠른 시작 가이드가 있는데, 이 가이드를 사용해서 sudo 사용자를 만들고 기타 보안 설정을 해 줍니다. 설정이 완료되면 다음 단계로 넘어갑니다.

/etc/ssh/sshd_config 파일은 수정해서 #GatewayPorts noGatewayPorts yes로 변경해줍니다. (앞에 있는 해시태그를 삭제한 다음 noyes로 변경합니다.)

파일을 저장한 다음, sudo service sshd restart를 사용해서 ssh 서버 서비스를 재시작시킵니다. 이때 연결이 잠시 끊길 수 있는데, 다시 접속하시면 됩니다. 연결이 되었으면 서버를 재부팅합니다.

3. 클라이언트 설정

이제 홈 서버/연결하고 싶은 클라이언트에서 설정을 시작합니다. 예를 들어, 집에 있는 서버의 9000번 포트에 외부 서버의 80번 포트를 연결해보겠습니다. 연결 경로는 다음과 같습니다:

사용자 –> 외부 서버 XXX.XXX.XXX.XXX (포트 80) –> 홈 서버 (포트 9000)

nat-3

이렇게 연결을 설정하려면 홈 서버에서 다음 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에 웹 서버가 돌아가고 있다고 가정합니다. 만약 외부 서버의 포트 80443을 통해 이 장치에 연결하고 싶다면, 홈 서버에서 다음 명령을 실행합니다:

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 # 아니면 한번에 다

연결 경로는 다음 그림과 같습니다:

nat-4

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 설정 부분은 이 가이드에서 참고를 많이 했습니다. 만약 추가로 설정하고 싶으신 부분이 있다면 확인해보세요! 원글 작성자에게 감사드립니다.

댓글