WireGuard를 사용해서 안전하게 외부에서 홈서버로 접속 할 수 있는 터널을 구축해보자

WireGuard를 사용해서 안전하게 외부에서 홈서버로 접속 할 수 있는 터널을 구축해보자

WireGuard는 가벼운 VPN 서비스이다. 서버와 클라이언트 간에 안전한 터널을 구축하여 통신 할 수 있게 해주는 서비스.

집에서 자기만의 홈서버를 구축하고, 그 안에서 돌아가는 각 종 서비스와 앱을 외부에서도 접속 가능하게 구현하고 싶은 경우, 일반적으로는 DDNS 설정 후, 라우터에 포트를 열어주고 포워딩 하는 방식을 많이 사용한다. 하지만 이러한 방식의 경우 집의 IP 주소가 외부에 노출되기 때문에 공격을 받는 경우 인터넷을 사용할 수 없게 될 가능성도 있다.

또한 ISP측에서 CG-NAT으로 구성해 놓은 경우, 애초에 내부 서비스를 외부로 공개하는 방법이 터널링 밖에 없다.

Synology DSM 같은 경우는 quickconnect로 설정시, Synology 서버를 중간에 경유하여 들어오는 터널링 서비스를 사용하기 때문에 CG-NAT 같은 상황을 우회 할 수 있지만, Synology 서버를 거치는 만큼 지연이 생긴다.

터널링 하는 방법은 Cloudflare 같은 서비스를 이용해서 무료로 구축하는 것도 가능은 하지만, 이 역시 Cloudflare의 서버를 한번 거치는 방식이 된다.

이번 글에서는 중간 업체를 거치지 않고 본인이 사용하는 VPS (Virtual Private Server)와 Wireguard를 이용하여 안전한 VPN 터널링을 구축하고 홈 서버를 외부에서 접속 가능하게 하는 방법에 대해서 알아본다.

이용할 VPS는 Google Cloud의 Compute Engine이다. Free Tier로 충분히 사용가능하다.


Google Cloud 설정

Google Cloud의 Compute Engine을 사용하는 경우, 몇가지 사전 설정이 필요하다.

방화벽 설정

Wireguard는 UDP 51820 포트를 사용하기 때문에 해당 포트를 열어주어야 한다. GCP 콘솔의 VPC 네트워크 => 방화벽 페이지로 이동하면 위쪽에 "방화벽 정책 만들기" 버튼과 "방화벽 규칙 만들기" 버튼이 있다. "방화벽 규칙 만들기" 버튼을 클릭.

이름은 나중에 알기 쉽게 wireguard.
네트워크는 default. 인스턴스에 다른 네트워크를 사용할 경우에는 해당 네트워크를 선택.
트래픽 방향은 인그레스.
소스 IPv4 범위는 0.0.0.0/0. 모든 IP에서 접속 가능하게 하는 설정이다. 만약 특정 IP에서만 접속 가능하게 하고 싶은 경우에는 여기에서 설정해주면 된다.
지정된 프로토콜 및 포트에서 UDP 체크해주고 51820.
마지막으로 만들기 버튼을 클릭하면 된다.

이것으로 방화벽 설정은 끝.

인스턴스 설정

머신 구성, OS, 데이터 보호등의 설정은 원하는 것을 설정해주면 된다. Wireguard 서버를 운영하는 목적이라면 Free Tier로 충분하기 때문에 그에 맞는 설정을 해주면 된다. 필자는 Ubuntu를 OS로 설정하였다.

중요한 건 네트워킹 설정이다. 여기서 IP 전달 => 사용 설정에 체크를 만드시 해줘야 한다. 그렇지 않으면 Wireguard에 연결된 클라이언트 머신이 인터넷에 접속이 되지 않는다.

만약 기존에 사용하고 있는 인스턴스를 활용하고 싶은데 IP 전달이 활성화 되어있지 않은 경우는 이 포스팅을 참고하여 설정을 변경해주면 된다.

방화벽 설정에 HTTP 트래픽 허용, HTTPS 트래픽 허용도 해주면 된다. 그래야 브라우저로 접속이 가능해진다.


Wireguard Server 설정

Compute Engine의 인스턴스를 올렸으면 SSH로 접속해주자.
우선 Wireguard 설치

sudo apt install wireguard

설치했으면 PrivateKey와 PublicKey를 생성해준다. 이 Key로 Server와 Client가 암호화 된 통신이 가능해지는 것이다.

wg genkey | tee privatekey | wg pubkey > publickey

이렇게 하면 privatekey 파일과 publickey 파일이 생성되었을 것이다.
두 파일 모두 /etc/wireguard 디렉토리로 옮겨주자.

sudo mv privatekey /etc/wireguard
sudo mv publickey /etc/wireguard

Wireguard Server에서 사용 할 privatekey 값을 표시하고 복사하자.

sudo cat /etc/wireguard/privatekey

서버가 어느 인터페이스를 통해서 인터넷에 연결되었는지 확인.

ip -o -4 route show to default | awk '{print $5}'

인스턴스에 ubuntu 설치한 경우 보통 ens4지만 다르게 나올 수도 있으니 확인이 필요하다.

그리고 Wireguard Server용 Config 파일을 생성.

sudo nano /etc/wireguard/wg0.conf

아래와 같이 설정 값을 넣어주자.

[Interface]
Address = 10.1.10.1/24 #서버의 Wireguard 네트워크상 주소
PrivateKey = <privatekey값>
ListenPort = 51820
MTU = 1360
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o <네트워크인터페이스> -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o <네트워크인터페이스> -j MASQUERADE

[Peer]
PublicKey = <클라이언트의publickey>
AllowedIPs = 10.1.10.2/32 #클라이언트의 Wireguard 네트워크상 주소

Address는 임의의 내부 주소를 아무거나 설정해주면 된다.
MTU는 GCP의 제약으로 1360으로 해주어야한다고 한다.
PostUp은 Wireguard 서버가 실행되었을 때, 접속한 Wireguard 클라이언트가 Wireguard 서버를 통해서 외부 인터넷과 연결되게 라우팅 해주는 설정이다.
PostDown은 Wireguard 서버를 중단했을 때 PostUp에서 설정한 값을 모두 중단하는 설정이다.

클라이언트의 publickey는 아직 생성전이기 때문에 일단 빈 값으로 둬도 된다.

Wireguard 설정 파일을 저장했으면 이번엔 IP 전달이 되게 서버의 설정을 변경해야한다.

sudo nano /etc/sysctl.conf

파일을 열면 #net.ipv4.ip_forward=1 이라는 줄이 있을텐데 #를 지워서 코맨트 해제.
파일 저장하고 아래 커맨드로 적용.

sudo sysctl -p

Wireguard 서버 실행

sudo wg-quick up wg0

올바르게 실행됐는지 다음 커맨드로 확인

sudo wg show wg0

public key:의 값이 sudo cat /etc/wireguard/publickey의 값과 같은지 확인.

마지막으로 서버가 부팅 했을 때 자동으로 Wireguard 서버도 실행되게 설정하면 끝이다.

sudo systemctl enable wg-quick@wg0

MTU와 Address가 맞게 설정됐는지 확인

ifconfig

wg0의 값들을 보면 된다.

MTU 값이 잘 설정되지 않았을 때는 다음 커맨드로 설정해주자.

sudo ip link set dev wg0 mtu 1360

보안을 위해서 파일 퍼미션을 root만 접속 가능하게 만들어두면 더 좋다.

sudo chmod 600 /etc/wireguard/wg0.conf
sudo chmod 600 /etc/wireguard/privatekey
sudo chmod 600 /etc/wireguard/publickey

Wireguard Client 설정

Client의 설정은 기본적으로 Server와 유사하다. 우선 홈서버에 wireguard를 설치.

sudo apt install wireguard

PublicKey와 PrivateKey 생성

wg genkey | tee privatekey | wg pubkey > publickey

두 파일 모두 /etc/wireguard 디렉토리로 이동.

sudo mv privatekey /etc/wireguard
sudo mv publickey /etc/wireguard

그리고 Wireguard Server용 Config 파일을 생성.

sudo nano /etc/wireguard/wg0.conf

설정 값.

[Interface]
Address = 10.1.10.2/24 #클라이언트 IP 주소
PrivateKey = <클라이언트privatekey>
MTU = 1360

[Peer]
PublicKey = <서버의publickey>
Endpoint = <compute engine 인스턴스ip주소>:51820
AllowedIPs = 0.0.0.0/0 #모든 IP로의 패킷을 Wireguard Server로 보냄

PersistentKeepalive = 25 #NAT바인딩용

Wireguard Client 디바이스가 Wireguard Server (Compute Engine Instance) 경유로 인터넷으로 접속하길 원하는 경우는 AllowedIPs = 0.0.0.0/0을 사용한다.

Wireguard Client 디바이스가 그냥 본인의 LAN 경유로 인터넷으로 접속하길 원하는 경우는 AllowedIPs 부분을 삭제하면 된다.

여기까지 했으면 클라이언트의 publickey값을 서버의 wg0.conf 파일에 넣어주자.

그 후 다시 클라이언트로 돌아와서 Wireguard 실행

sudo wg-quick up wg0

연결이 됐는지 ping으로 확인

ping 10.1.10.1

wg show로도 확인

sudo wg show wg0

last handshake: 값이 있으면 연결이 된 것으로 봐도 된다.

인터넷에 연결이 되는지도 확인

ping 8.8.8.8

클라이언트의 외부 IP가 어떻게 인식되는지 확인

curl https://api.ipify.org

AllowedIPs = 0.0.0.0/0으로 설정했을 경우, Compute Engine 인스턴스의 IP 주소가 나오면 성공.

모두 확인했으면 마지막으로 서버 부팅시에 자동으로 Wireguard 실행되게 설정.

sudo systemctl enable wg-quick@wg0

만약 복수의 홈서버를 연결하고 싶다면 같은 방법으로 클라이언트의 IP만 바꿔서 설정해주면 된다.
클라이언트를 추가 할 때마다 서버의 wg0.conf 설정에 Peer를 추가해주는 것도 잊지 말자.

서버 때와 마찬가지로 보안을 위해서 파일 퍼미션을 root만 접속 가능하게 만들어두면 더 좋다.

sudo chmod 600 /etc/wireguard/wg0.conf
sudo chmod 600 /etc/wireguard/privatekey
sudo chmod 600 /etc/wireguard/publickey

내부 서비스로 연결

Wireguard로 서버와 클라이언트가 연결되었으면 거의 다 끝난거나 마찬가지다.
이제 홈 서버에 원하는 서비스를 올리고 외부로 노출되는 포트 번호를 지정하자.

예제로는 다음과 같은 값을 사용한다

  • Google Compute Engine Instance IP: 35.1.2.3
  • Wireguard Client IP: 10.1.10.2
  • 홈 서버에 올린 서비스 포트: 1234
  • 도메인: service1.mydomain.com

DNS에 35.1.2.3에 연결되는 service1이라는 A 레코트를 추가해준다.
그 다음 서버 (Google Compute Engine Instance) 쪽에 nginx reverse proxy 설정을 해주면 끝이다.

server {
    server_name  service1.mydomain.com;
    access_log /var/log/nginx/service1.log;
    error_log  /var/log/nginx/service1-error.log error;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://10.1.10.2:1234;
        proxy_redirect off;
    }
}

proxy_pass에 Wireguard Client IP주소와 서비스 포트번호를 넣어주면 된다.

certbot으로 SSL 추가하는 것도 잊지 말자.


꼭 내부 서비스 연결용이 아니더라도 나만의 VPN 서버를 VPS를 통해서 구축하는 방법을 알아두는 것만으로도 많은 공부가 되었다. 홈 서버를 운영하는 분들은 이 방법을 통해서 조금 더 다양한 실험과 시도를 해볼 수 있을 것이라고 생각한다.