네트워크 공부 & 실습/네트워크 실습

[VPN] Raspberry Pi 를 VPN 의 EndPoint 로 만들기

강_토발즈 2025. 5. 26. 20:41

 

 

 

앞서 NAS에 시도해봤던 OpenVPN 은 접속은 되었으나, 인터넷이 되지 않았던 안좋은 기억이 있기 때문에, 이번에는 WireGuard 라는 VPN 프로그램을 이용하여 Raspberry Pi 에 설치하고, 집안의 네트워크들이 동작 중인 서브넷을 외부에서 접속하는 것을 시도해 보자.

 

 

1. WireGuard Package 설치하기

 

먼저 SSH 프로토콜로 Raspberry Pi 에 접속하고, apt update 후, wireguard 패키지를 설치해준다.

 

ssh kang@192.168.0.54

sudo apt update

sudo apt install wireguard

 

 

 

2. 키 생성하기

 

2-1. VPN 을 설정하는 데 왜 '키 생성'을 해야하나?

라즈베리파이에 WireGuard VPN을 설치하고 나면, 대부분 가이드에서 처음에 wg genkey로 키를 생성하라고 한다.
공부해 보니, 이 '키 생성'은 VPN에서 서로를 안전하게 인증하는 데 핵심 역할을 한다. WireGuard 의 키 인증 방법과 구조(?) 에 대해 간략히 정리하자면

- WireGuard 는 비밀번호가 아니라, '키 쌍'으로 인증하는 시스템이다. 라즈베리 파이에 ssh 로 접속하거나, 다른 pc에 로그인 할 땐 ID / PW 를 사용하지만, WireGuard 는  '공개키 기반 암호화'라는 방식을 쓴다. 서버와 클라이언트가 각자 "개인키(private key)"와 "공개키(public key)" 한 쌍씩 만들어 놓고, 서로의 공개키만 알고 있으면 안전하게 통신할 수 있는 구조다.

 

 

2-2. 키 생성 명령어

umask 077
wg genkey | tee privatekey | wg pubkey > publickey

이렇게 하면 두 개의 파일이 만들어진다:

  • privatekey: 내 비밀키 (절대 유출 금지)
  • publickey: 상대에게 줄 공개키

이 키들을 설정 파일에 잘 넣으면, 서버도 나를 허용해주고, 나도 서버에 접속할 수 있게 된다.

cat publickey
cat privatekey

 

위 명렁어를 입력해서 무작위 난수가 나오면 제대로 설정이 된 것이다.

 

 

3. 설정파일 생성 및 작성

 

3-1. etc 경로 아래에 있는 wireguard 폴더 아래에 설정파일(wg0.conf)을 만들어야 한다.

sudo vi /etc/wireguard/wg0.conf

 

편집기는 익숙한 vi 편집기로 사용한다.

 

  • PirvateKey 는 key 를 생성하고 cat 으로 확인하면 반환되는 키 값을 넣어준다.

  • Address 는, VPN 인터페이스의 IP 주소를 의미하고, 이후  클라이언트가 접속하면 할당받을 IP 대역을 설정하는 것 이기 때문에 커스터마이징 하고 싶은 것이 아니면, 위와 같이 임의로 설정해도 무방하다.

 

4.인터페이스 활성화

 

sudo systemctl start wg-quick@wg0

sudo wg

sudo systemctl enable wg-quick@wg0

 

위의 명령어대로 WireGuard 를 시작하고 활성화 한다.

 

  • sudo systemctl start wg-quick@wg0
    >> WireGuard 를 wg0 환경 설정을 적용하여 시작한다.

  • sudo wg
    >> Wireguard 확인
    wg0 환경설정 파일의 내용이 반환되어야 한다. (제대로 설정이 되었다면)

    sudo systemctl enable wg-quick@wg0
  • >> 시스템 재시작 시에도 WireGuard 가 실행되도록 설정한다.

 

 

5. 포트포워딩 & DDNS 셋팅

 

외부에서 우리집의 공인IP: 포트명 으로 접속을 시도하면 이 접속을 라즈베리 파이(VPN server)로 안내해주는 설정(포트 포워딩)을 해준다.

 

예전에 설정을 해 두었지만 DDNS 가 제대로 설정되어 있나 확인했다. 집 인터넷은 공인 IP가 수시로 바뀔 수 있어서, 외부에서 VPN 서버로 접속할 때 문제가 된다. 그래서 DDNS(Dynamic DNS) 를 설정해두면, 공인 IP가 바뀔 때마다 자동으로 도메인 주소에 연결된 IP도 갱신된다. 결국 (내가 설정한)문자열로 된 고정된 이름으로 언제든지 우리집 공유기를 찾을 수 있게 된다.

 

 

 


 

이렇게 까지 셋팅하면, 외부로 부터 접속을 시도하면 라즈베리파이 까지 연결이 되도록 설정이 완료된 상태이다. (외부 접속을 가정해서, DDNS - 포트포워딩 - 인터페이스 - 키&값 확인 의 과정과 반대로 설정을 했다.)

이제 WireGuard VPN 의 클라이언트 셋팅을 하도록 하자.

앞서 언급했던 것과 같이, WireGuard 는 키-값 이 일치하면 연결을 수락하는 방식이기 때문에, 현재 VPN 의 서버측(라즈베리파이)은 셋팅이 끝났고, 클라이언트 측에 필요한( 외부 IP를 통한 접속 시도)키 생성 및 환경설정 파일을 작성하도록 하자.

 

 

6. 라즈베리파이(서버) 에서 클라이언트 키 만들기

등록 된 사용자만 접근이 가능하도록, 서버에서 클라이언트 키를 생성한다. 

 

umaks 077
wg genkey | tee client_privatekey | wg pubkey > client_publickey

 

 

키가 만들어졌으니 서버 설정파일(wg0.conf) 에 클라이언트 키 를 등록 해준다.

 

sudo vi /etc/wireguard/wg0.conf

 

 

  • [Peer] 이하 문장을 작성해주고, client-public key 를 입력해주고, 설정파일을 저장한다. 

  • AllowedIPs 값은 해당 키로 접속하는 클라이언트에게 10.0.0.2 의 IP 를 부여한다는 의미이다.



7. 맥북에 WireGuard 설치 후 설정파일 작성하기

 

7-1. 맥북에 Wireguard 설치하기

 

현재 맥북에 SSH 접속 중이므로 CLI 를 통해 설치하도록 한다.

 

brew install wireguard-tools

 

 

7-2. 설정 파일을 작성하고 저장, 종료한다.

vi /Users/{사용자이름}/wireguard/client.conf

 

[Interface]
PrivateKey = <여기에 client_privatekey>
Address = 10.0.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = <여기에 server_publickey>
Endpoint = <DDNS 또는 공인IP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

 

 




8. 인터페이스 생성 및  연결 시도

 

8-1. 연결하기

sudo wg-quick up ./client.conf

 

conf 파일이 있는 곳에서 실행한다.

 

 

DDNS 가 제대로 입력되었다면, 라우터 설정에서 볼 수있는 우리집의 공인 IP가 출력되고, 게이트웨이 주소까지 제대로 반환되는 것을 확인할 수 있다.

 

8-2. 연결 확인하기

 

sudo wg

 

현재 접속 정보가 반환된다. ifconfig 를 통해 네트워크 정보를 확인하면 utun8 인터페이스가 10.0.0.2 IP 를 할당 받은 것을 확인할 수 있다.

 

 

9. NAT (마스커레이드) 설정, IP 포워딩 설정

위의 셋팅을 통해, 클라이언트(맥북)와 서버(라즈베리파이) 간에 VPN 연결이 완료 되었다. 하지만 VPN 터널은 단순 통로 가 생긴 것 뿐이다. 즉 클라이언트에서 -> 서버로 패킷을 보내도 패킷이 언제 어디로 가야할 지 모르기 때문에 서버 안에서 패킷이 죽어버리는 상황이 발생한다. 

따라서 서버로 들어온 패킷이 어디로 가야하는지, 또 어디서 보내는 것인지 설정을 해 줘야 제대로 통신이 가능하다. 즉,

  • IP 포워딩은 패킷이 움직이게 해주는 신호등
  • NAT는 VPN을 통해 온 패킷이 라즈베리파이 ‘인 척’ 나갈 수 있게 해주는 변장술

이 두 가지 셋팅이 없으면, 맥북에서 보내는 트래픽은 라즈베리파이에서 갇혀서 멍하니 기다리기만 한다. (ping 도 안되고, 인터넷도 안된다.)

 

 

9-1. VPN을 통해 들어온 트래픽은 처음에 라즈베리파이의 wg0 인터페이스로 도착한다. 그런데 IP 포워딩이 꺼져 있으면 그 트래픽은 거기서 멈춘다. 아래 명령어 한 줄이 들어온 패킷을 다른 인터페이스로도 보내줄 수 있어 라는 허락이다.

sudo sysctl -w net.ipv4.ip_forward=1



9-2. 내부망(192.168.0.x)에 있는 다른 장비나, 인터넷을 향해 나가는 트래픽은 VPN을 통해 들어온 맥북(10.0.0.2)의 IP를 전혀 모른다. 그래서 패킷을 받더라도 "어디서 온 거야?" 하고 무시해버릴 수 있다. 그래서 라즈베리파이가 중간에서 이걸 자기 IP(예: 192.168.0.54) 인 척하고 대신 보내줘야 한다. 이게 바로 NAT(MASQUERADE)다.

sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

 

 

9-3.  클라이언트(맥북) 에서는 en0 이라는 무선연결 인터페이스로도 패킷을 주고받고 있기 때문에, VPN 이 연결되어도 이 인터페이스로 통신을 할 수도 있다. 따라서 10.0.0.2 라는 IP 로 통신을 한다면, en0 인터페이스가 아니라, VPN 인터페이스인 utun8 을 이용해서 10.0.0.1 인 라즈베리 파이로 패킷이 가도록 설정해야 한다.

추가로 집안에 있는 네트워크 기기들에도 접근하기 위해 (192.168.0.0/24) 해당 서브넷도 utun8 로 연결되도록 추가한다.

 sudo route add -net 10.0.0.0/24 -interface utun8
 sudo route add -net 192.168.0.0/24 -interface utun8

 

위의 모든 설정을 적용하고, 라즈베리파이 (10.0.0.1) -> 맥북 (10.0.0.2) 의 ping test, 또 반대로의 ping test 를 실시한다.

Server -> Client
Client -> Server

 

 

양방향 ping test 는 성공하였다. 하지만 맥북(클라이언트)이 집 안의 WiFi 에 연결되어 있기 때문에, 이를 외부 네트워크에 연결하고, 이제 정말 외부에서 VPN 서버로 접속하고, 같은 서브넷에 있는 기기중 하나에 연결해보도록 하자.

 

 

10. 외부에서 VPN 접속 하기 

 

10-1. 먼저 집 안의 WiFi 연결을 끊고, 모바일 핫스팟으로 네트워크를 연결해준다.

 

sudo systemctl enable wg-quick@wg0

 

 

내가 켜 놓은 핫스팟으로 연결한다. 신사답게.

이후 내 IP 주소를 검색해보면, 라우터를 통해 나가는 211 로 시작하는 IP 가 아닌, 다른 IP 를 할당 받은 것을 알 수 있다.

 

집에서 WiFi 를 연결하면, 라우터를 통해 인터넷과 통신하므로 아이피를 검색하면 211 이하로 시작하는 IP 가 나온다.

 

 

10-2. 명령어로 192.168.0.27 (데스크탑) 을 향해 가는 패킷은 어떤 인터페이스를 통해 가는지 확인한다.

 sudo route get 192.168.0.27

 

 

192.168.0.27 이라는 ip 는 내가 설정한 VPN 인터페이스인 utun8 을 이용하는 것을 확인할 수 있다. 또 현재 외부 네트워크에 접속한 상태임에도 192.168.0.27 과 ping test 에 성공하는 것을 알 수 있다.

 

10-3. 집 안에 있는 NAS 에 접속해보기

 

마지막으로 [외부 접속] -> [클라이언트(맥북)] -> [서버(라즈베리파이)] -> [NAS] 연결을 검증해본다.

라즈베리파이와 같은 서브넷에 있는 NAS 는 192.168.0.20 의 주소를 가지고 있다. 따라서 VPN 에 연결한 후 ssh 연결을 시도한다.

ssh kkace22@192.168.0.20

 

 

외부에서 접속한 서버임에도 집 안에 있는 NAS 에 성공적으로 접속하였다. 접속 과정또한 검증하기 위해 traceroute 를 실행 해 보았다.

 

현재 접속한 기기(맥북) 에서 10.0.0.1 (라즈베리파이) 로 먼저 접속을 하고, 그 이후 192.168.0.20 인 NAS 로 접속한 것을 확인하였다. 내가 생각한 접속 경로와 100% 일치하는 것을 확인할 수 있었다.

 

     [인터넷]
         │
         │  (Hot Spot)
         ▼

[맥북 (외부 네트워크)]
   (IP: 10.0.0.2)
         │
         │  WireGuard VPN (utun8)
         ▼
[라즈베리파이 (VPN 서버)]
   - wg0 인터페이스: 10.0.0.1
   - LAN 인터페이스: 192.168.0.54
         │
         │  로컬 서브넷 (192.168.0.0/24)
         ▼
[NAS (내부 장비)]
   - IP: 192.168.0.20

 

 

11. 마무리

 

- 라즈베리 파이에서 설정파일이 부팅시에 동작하도록 적용해준다.

sudo systemctl enable wg-quick@wg0

 

- 클라이언트 설정은 재부팅 하면 사라지기 때문에, NAT 설정과, IP 포워딩 설정도 저장한다.

# IP 포워딩 저장

sudo vi /etc/sysctl.conf

net.ipv4.ip_forward=1

sudo sysctl -p
  • vi 편집기를 열고 두번 째 항목을 맨 아래 부분에 작성한 뒤 저장하고 나오고, sysctl -p 로 저장한다.
# NAT 설정 저장

sudo apt install iptables-persistent

sudo iptables-save > /etc/iptables/rules.v4

 

 

위의 설정으로, 서버와 클라이언트가 재부팅 되더라도 다시 VPN 인터페이스를 통해 서로 연결될 수 있도록 하였다.

VPN 설정부터 연결, 그리고 같은 서브넷에 접속하기 까지 꽤 오랜 시간 Setting 을 했다. 생각보다 시간이 많이 걸렸지만, 지난번 OpenVPN의 접속실패 결과를 벗어나, 이번엔 보다 완벽하게 연결 및 접속에 성공해서 뿌듯하다.
직접 설정을 하면서 상상만 할 수 있었던 네트워크의 흐름을 직접적으로 확인할 수 있었다. 이렇게 외부에서 접속해서 집안에 기기들에 접속할 수 있다고 생각하니 보안에 더 신경을 써야하는 기술임이 분명하다는 생각도 들었다. 이제 외부에서 접속하여 할 수 있는 것들에 대해 생각해보고, 라즈베리파이에 자동화 스크립트들을 옮기는 작업도 시작해야겠다.