Linux VPS에 WireGuard VPN 직접 구축하기
Linux VPS에서 WireGuard VPN을 직접 구축하는 방법을 상세히 안내합니다. 키 생성과 wg0.conf 설정부터 IP 포워딩, NAT 규칙, 방화벽 구성 및 흔히 발생하는 핸드셰이크 오류 해결법까지 실무적인 핵심 설정 과정을 모두 다룹니다.
구축할 내용
직접 소유한 서버에 WireGuard VPN을 구축하는 과정은 약 40줄의 설정으로 이루어집니다. 키 쌍 1개, 인터페이스 파일 1개, sysctl 설정 1개, NAT 규칙 1개, 방화벽 포트 개방 1개가 필요합니다. 설치 자체는 간단하므로, 이 가이드의 대부분은 발생 가능한 문제, 키 권한, AllowedIPs, 포워딩 및 DNS 설정에 할애합니다.
WireGuard는 Linux 5.6 버전부터 메인라인에 포함된 커널 수준의 Layer 3 터널입니다. 따라서 Ubuntu 24.04나 Debian 13에서는 별도의 외부 모듈 없이 바로 사용할 수 있습니다. 암호화 방식 협상, 인증 기관(CA), 사용자 이름/비밀번호 단계가 없으며, 피어는 공개 키와 해당 키가 사용할 수 있는 IP 주소의 조합으로 정의됩니다. MAC 검사에 실패한 패킷은 응답 없이 폐기되므로, 포트 스캔을 수행해도 아무런 응답을 하지 않습니다. 반면, 별도의 인증 서버가 존재하지 않으므로 접근 권한을 제거하려면 서버에서 해당 피어를 삭제해야 합니다.
가상화 환경을 먼저 확인하십시오
WireGuard는 커널 모듈을 로드할 수 있는 환경이 필요하며, KVM VPS에서는 별도의 설정 없이 바로 작동합니다. 호스트 커널을 공유하는 컨테이너 가상화 방식인 OpenVZ나 LXC에서는 첫 번째 명령이 RTNETLINK answers: Operation not supported 오류와 함께 실패하며, 이 경우 wireguard-go 사용자 공간 구현을 대체제로 사용해야 합니다. 먼저 sudo modprobe wireguard && echo ok 명령으로 확인하십시오.
키를 유출하지 않고 생성하기
읽기 권한이 모두에게 열린 /etc/wireguard/server.key는 VPN을 사용하지 않는 것과 다름없습니다. 일반적인 umask 077 && wg genkey | sudo tee ... 라인은 신뢰할 수 없습니다. sudo가 tee로 생성된 파일에 자체적인 umask를 적용하기 때문입니다. 모드를 명시적으로 설정하십시오.
sudo apt update && sudo apt install -y wireguard nftables
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'
sudo chmod 600 /etc/wireguard/server.key동일한 방식으로 클라이언트 키 쌍을 생성하십시오. wg genpsk은 선택 사항인 사전 공유 키(pre-shared key)를 추가하며, 각 설정 파일에 한 줄씩 입력합니다.
서버 인터페이스: /etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of /etc/wireguard/server.key>
[Peer]
PublicKey = <laptop public key>
PresharedKey = <psk, optional>
AllowedIPs = 10.8.0.2/32chmod 600 하십시오. 파일이 모든 사용자에게 접근 가능한 상태라는 경고가 시작 시 출력된다면 권한 설정을 건너뛴 것입니다. Address은 터널 내부의 서버 주소이며, 전체 VPN 서브넷의 마스크를 포함합니다. 실제 네트워크 환경에서 사용되지 않을 대역을 선택하십시오. 192.168.1.0/24는 클라이언트가 위치한 가정용 공유기의 절반 이상과 충돌하며, 이 경우 터널은 로컬 경로와의 충돌로 인해 아무런 알림 없이 통신이 단절됩니다.
서버 측 피어의 AllowedIPs은 /32이며, 이는 해당 클라이언트가 소유한 단일 터널 주소입니다. 두 피어에 동일한 allowed IP를 설정하면 마지막으로 구성된 피어로 연결이 이동하며, 먼저 설정된 피어는 오류 메시지 없이 트래픽 수신이 중단됩니다. SaveConfig를 설정하지 마십시오. 그렇지 않으면 wg-quick down이 라이브 상태를 기준으로 이 파일을 덮어씁니다.
서버를 라우터로 전환하기
Linux 서버는 자신에게 향하지 않은 패킷을 폐기합니다. 기본적으로 패킷 포워딩과 소스 NAT 기능은 비활성화되어 있습니다.
printf 'net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\n' \
| sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward단순한 sysctl -w 설정은 재부팅 전까지만 작동하며 이후에는 조용히 중단됩니다. NAT 설정에는 wg0가 아닌 인터넷에 연결된 외부 인터페이스(egress interface)가 필요합니다. eth0을 가정하지 마십시오. 최신 이미지에서는 enp1s0 또는 ens3와 같은 이름을 사용하므로 ip route show default에서 직접 확인해야 합니다.
방화벽: 포트 및 포워딩 경로
하나의 nftables 파일이 필터링과 NAT를 모두 처리합니다. /etc/nftables.conf을 작성하면 기존 규칙 세트가 초기화(flush)되므로, 이미 ufw나 Docker로 관리 중인 서버라면 이 단계를 건너뛰십시오.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iif lo accept
tcp dport 22 accept
udp dport 51820 accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
iifname "wg0" oifname "enp1s0" accept
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.8.0.0/24 oifname "enp1s0" masquerade
}
}sudo systemctl enable --now nftables를 사용하여 규칙을 적용하십시오. 이때 두 번째 SSH 세션을 반드시 열어 두어야 합니다. policy drop을 실행할 때 SSH 규칙에 오타가 있으면 서버 접속이 차단될 수 있습니다. 포워딩 체인이 허용하지 않는 범위, 즉 wg0에서 wg0까지의 설정을 확인하십시오. 피어는 인터넷에 접속할 수 있지만 서로 간의 통신은 불가능합니다. 피어 간 통신이 필요하다면 iifname "wg0" oifname "wg0" accept을 추가하십시오. 동일한 체인이 피어가 서버 자체의 어떤 자원에 접근할 수 있는지도 제어합니다. 이는 서버를 tmux에서 Claude Code를 실행하는 원격 개발 환경으로 함께 사용할 때, 해당 환경을 외부로 노출하고 싶지 않은 경우에 중요합니다.
ufw를 사용하는 서버의 경우: ufw allow 51820/udp을 실행하고, /etc/default/ufw 파일에 DEFAULT_FORWARD_POLICY="ACCEPT"을 추가한 뒤, /etc/ufw/before.rules 파일의 최상단에 *nat POSTROUTING MASQUERADE 규칙을 작성하십시오.
systemd를 통한 서비스 구동
sudo systemctl enable --now wg-quick@wg0
sudo wg showwg-quick는 인터페이스를 생성하고 주소를 추가하며 AllowedIPs에서 파생된 경로를 설치합니다. enable --now는 중요한 절반의 역할을 합니다. 수동으로 실행한 wg-quick up wg0는 재부팅 후 사라지며, 커널 업그레이드 시에는 재부팅이 필수적입니다. 재부팅 후 다시 시작되지 않는 유닛은 누군가 연결을 시도하기 전까지 침묵을 지킵니다. 따라서 자신의 ntfy 서버를 가리키는 wg-quick@wg0의 OnFailure= 드롭인 설정은, 차단된 사용자로부터 연락을 받기 전에 휴대폰으로 문제를 인지할 수 있는 가장 저렴한 방법입니다.
클라이언트 설정과 모두가 실수하는 설정
[Interface]
PrivateKey = <laptop private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25AllowedIPs은 두 가지 작업을 동시에 수행하며, 이 둘을 혼동하는 것이 WireGuard 설정에서 발생하는 대부분의 혼란의 원인입니다.
아웃바운드 측면에서 이는 라우팅 테이블입니다. 대상 주소가 피어의 AllowedIPs와 일치하는 패킷은 암호화되어 해당 피어로 전송됩니다. 0.0.0.0/0, ::/0은 모든 트래픽을 터널로 보내는 풀 터널(full tunnel) 방식으로, 서버를 기본 경로로 설정합니다. 스플릿 터널(split tunnel)은 더 좁은 범위의 목록을 사용합니다. AllowedIPs = 10.8.0.0/24, 10.20.0.0/16은 VPN 트래픽과 서버 뒤의 사설 네트워크 하나를 처리하며, 그 외의 모든 트래픽은 기존 로컬 경로를 유지합니다. 이러한 좁은 범위의 목록을 사용하면 서비스를 공용 인터넷에서 완전히 격리할 수 있습니다. 예를 들어 터널 주소에 바인딩된 VPS의 비공개 Nextcloud 인스턴스나 동일한 장비에서 실행 중인 중첩 가상화 랩 VM은 피어에게는 접근 가능하게 유지하면서 다른 외부 사용자에게는 보이지 않게 할 수 있습니다.
인바운드 측면에서 이는 접근 제어 목록(ACL)입니다. 피어로부터 복호화된 패킷의 출발지 주소가 해당 피어의 AllowedIPs에 포함되어 있지 않으면 패킷은 폐기됩니다. 서버가 노트북을 위해 10.8.0.2/32을 나열하는 이유가 바로 이것입니다. 만약 여기에 0.0.0.0/0를 설정하면 해당 클라이언트가 터널 내의 어떤 주소로든 스푸핑(spoofing)할 수 있게 됩니다.
PersistentKeepalive는 NAT 뒤에 있는 클라이언트를 위한 설정입니다. NAT 환경에서는 패킷이 흐를 때만 라우터가 UDP 매핑을 유지하기 때문입니다. 매핑이 만료되면 서버는 더 이상 클라이언트에 도달할 수 없습니다. PersistentKeepalive = 25는 이 매핑을 유지하는 역할을 합니다. 이 설정은 공인 IP를 가진 서버가 아닌 클라이언트에 적용하십시오.
DNS와 아무도 눈치채지 못하는 유출
AllowedIPs = 0.0.0.0/0이 있고 DNS = 라인이 없으면, 클라이언트는 로컬 네트워크에서 학습한 리졸버인 192.168.1.1의 카페 라우터를 계속 사용합니다. 해당 경로는 기본 경로보다 더 구체적이므로, 다른 모든 트래픽은 터널링되지만 DNS 쿼리는 로컬 링크를 통해 평문으로 전송됩니다. 트래픽은 비공개 상태이지만, 조회한 도메인 이름 목록은 그렇지 않습니다.
두 가지 정직한 방법이 있습니다. DNS를 퍼블릭 리졸버(DNS = 9.9.9.9)로 지정하면 쿼리가 터널을 타고 서버에서 나가게 되지만, 해당 리졸버는 여전히 쿼리 내용을 볼 수 있습니다. 또는 unbound이나 dnsmasq를 10.8.0.1에 바인딩하여 실행하고, DNS = 10.8.0.1를 설정한 뒤, 입력 체인(input chain)에 udp dport 53 iifname "wg0" accept를 추가하십시오. 해당 라인을 설정하고 리졸버를 잊어버리면, 아무것도 해석되지 않습니다.
Linux 클라이언트에서 wg-quick은 DNS을 통해 resolvconf을 적용합니다. 이 설정이 없으면 resolvconf: command not found가 적용됩니다. openresolv을 설치하거나, systemd-resolved를 사용하는 클라이언트라면 PostUp = resolvectl dns %i 10.8.0.1을 설정하십시오.
터널 연결을 끊지 않고 피어 추가 및 제거하기
인터페이스를 재시작하여 사용자를 추가하면 연결된 모든 사용자의 접속이 끊깁니다. [Peer] 블록을 wg0.conf에 추가한 다음, 피어 세트를 현재 상태에서 다시 로드하십시오.
sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'wg-quick strip는 wg-quick 전용 키(Address, DNS, PostUp)를 제외한 설정을 출력하며, syncconf은 라이브 세션을 유지하면서 변경 사항을 적용합니다. 이 명령은 피어만 업데이트합니다. Address가 변경된 경우에는 여전히 전체 down/up 과정이 필요합니다. sudo wg set wg0 peer <public key> remove으로 피어 권한을 취소한 뒤, 파일에서 해당 블록을 삭제하십시오. 삭제하지 않으면 다음 번 다시 로드 시 해당 피어가 다시 생성됩니다.
실패 유형 및 확인 가능한 메시지
핸드셰이크가 완료되지 않음. wg show에 피어는 표시되지만 latest handshake가 없으며, 클라이언트 로그에는 다음과 같이 기록됩니다.
Handshake for peer 1 (10.0.0.10:51820) did not complete after 5 seconds, retrying (try 2)데이터가 도착하지 않거나 수락되지 않는 상태입니다. 다음 순서대로 확인하십시오. VPS 방화벽과 제공업체의 네트워크 방화벽(대부분의 제어판에서 별도로 관리됨)에서 UDP 51820 포트가 열려 있는지, Endpoint 주소와 포트가 올바른지, 키가 서로 바뀌지 않았는지 확인하십시오. 클라이언트의 [Peer] 블록에 있는 키는 반드시 서버의 공개 키여야 하며, 그 반대도 마찬가지입니다. 개인 키를 붙여넣거나 클라이언트 자신의 공개 키를 넣으면 정확히 이 증상이 나타납니다. 서버에서 sudo tcpdump -ni any udp port 51820를 실행하면 패킷이 실제로 도착하는지 확인할 수 있습니다. 커널 모듈은 기본적으로 아무것도 기록하지 않습니다. WireGuard 메시지는 동적 디버그(echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control)를 활성화해야만 dmesg에 나타나며, 이 상태에서 키가 일치하지 않으면 잘못된 MAC으로 인한 폐기 메시지가 표시됩니다.
핸드셰이크는 성공하나 인터넷이 안 됨. ping 10.8.0.1은 성공하지만 ping 1.1.1.1에서 타임아웃이 발생한다면 포워딩이나 NAT 설정이 누락된 것입니다. sysctl net.ipv4.ip_forward이 1로 설정되어 있는지 확인한 후, 클라이언트에서 핑을 보내는 동안 sudo nft list ruleset 또는 sudo iptables -t nat -L POSTROUTING -n -v으로 카운터를 관찰하십시오. 매스커레이드(masquerade) 규칙의 패킷 카운터가 0이라면 송신 인터페이스 이름이 잘못된 것이며, 카운터는 올라가는데 응답이 없다면 포워드 체인 정책을 확인해야 합니다.
인터넷은 되나 도메인 이름 해석이 안 됨. ping 1.1.1.1는 성공하지만 curl https://example.com가 Could not resolve host을 반환합니다. DNS 줄이 누락되었거나, 터널 내부에서 접근할 수 없는 리졸버를 지정한 경우입니다.
일부 HTTPS 사이트에서 응답이 없음. SSH와 핑은 정상이나 큰 페이지를 불러올 때 멈춥니다. 이는 경로 MTU 문제입니다. 터널은 오버헤드를 추가하는데, 중간의 링크가 ICMP 메시지 없이 너무 큰 패킷을 폐기하기 때문입니다. 클라이언트 [Interface]의 MTU 값을 낮추십시오. 1420, 1380, 1280 순으로 시도해 보십시오. MTU를 낮춰서 멈춤 현상이 해결되었음에도 처리량이 만족스럽지 않다면, 임의의 숫자를 추측하지 말고 이분 탐색과 TCP MSS 클램핑을 통한 실제 경로 MTU 찾기를 수행하십시오. 이 과정은 터널과 무관한 다른 원인들도 배제해 줍니다.
인터페이스가 시작되지 않음. Address already in use은 다른 프로세스가 UDP 51820 포트를 점유하고 있음을 의미합니다. up 실패 후 Cannot find device wg0가 나타난다면 설정이 거부된 것이므로 journalctl -u wg-quick@wg0 -n 50을 읽어 보십시오.
Streisand 또는 OpenVPN에서 마이그레이션
Streisand는 더 이상 유지보수되지 않으며 저장소도 보관 처리되었습니다. 업데이트가 중단된 자동화 도구로 VPN을 운영하는 것은 보안상 심각한 위험을 초래합니다. 제자리 업그레이드는 불가능하며, OpenVPN의 PKI는 변환할 수 없습니다. WireGuard는 인증서, CA, 만료 개념이 없으므로 모든 클라이언트는 새로운 키 쌍을 발급받아야 합니다.
병렬로 마이그레이션을 진행하십시오. UDP 51820 포트의 WireGuard는 동일한 서버에서 1194 포트의 OpenVPN과 공존할 수 있습니다. wg0을 구축하고 클라이언트를 하나씩 이동시킨 뒤, 기존 서비스를 중단하십시오. OpenVPN의 사용자 이름/비밀번호 및 폐기 모델은 그대로 이전되지 않습니다. 계정 관리나 감사 추적이 필요하다면 WireGuard 상위 계층에서 해당 기능을 구현하십시오.
백업, 업그레이드 및 규모 확장 시의 부하
/etc/wireguard가 곧 서버입니다. 이를 백업하고(sudo tar czf wg-backup.tgz -C /etc wireguard, 모드 600, 서버 외부 보관) 나면 새로운 VPS에서 몇 분 안에 복구할 수 있습니다. 서버의 개인 키를 분실하면 모든 클라이언트가 서버의 공개 키를 고정(pinning)해 두었기 때문에 모든 클라이언트 설정을 다시 발급해야 합니다. 업그레이드는 일반적인 apt upgrade 명령과 커널 업데이트를 위한 재부팅이면 충분하며, wg-quick@wg0은 활성화해 두었다면 스스로 다시 시작됩니다.
피어별 상태 정보는 작고 암호화는 커널에서 수행되므로, 성능의 한계는 이 설정이 아니라 VPS의 CPU와 대역폭 할당량에 달려 있습니다. 공개된 수치를 신뢰하기보다 iperf3를 사용하여 터널을 통해 직접 측정하십시오. 규모가 커질 때 문제가 되는 것은 운영입니다. 모든 피어는 고유한 터널 IP가 필요하며, 60개의 [Peer] 블록을 직접 수정하다 보면 AllowedIPs가 중복되는 실수가 발생하기 쉽습니다. 스크립트로 설정을 생성하십시오. 서버 하나는 하나의 UDP 엔드포인트이자 단일 장애 지점이며, WireGuard는 클러스터링을 지원하지 않습니다. 따라서 이중화란 고유한 키를 가진 두 번째 서버를 운영하는 것을 의미합니다. 키 교체는 수동으로 이루어지므로, 누가 어떤 키를 가지고 있는지, 키를 어떻게 폐기할지 기록해 두어야 합니다. 이러한 관리 업무가 텍스트 파일로 감당하기 어려워지면, 보통 동일한 커널 데이터 평면 위에 제어 평면을 구축하는 방식을 택합니다. 직접 호스팅하는 NetBird 서버는 수동으로 처리하던 주소 할당, 피어 배포 및 설정 키 관리를 대신 수행합니다. 제어 평면을 직접 운영하는 것이 부담스럽다면 Tailscale이 이를 대신 호스팅해 줍니다. Tailscale의 무료 플랜은 6명의 사용자와 무제한 기기를 지원하며, 대부분의 개인용 네트워크 환경에서는 충분히 무료로 사용할 수 있습니다. 그 이상의 규모가 되면 기기 수가 아닌 사람 수에 따라 비용이 발생하므로, 가정이나 소규모 팀이 실제로 지불하는 비용은 wg0.conf에 수동으로 입력해야 했던 피어의 수가 아니라 로그인 권한을 가진 사람의 수에 따라 결정됩니다. 이 단계에서는 스플릿 터널 AllowedIPs 관리가 서브넷 라우터에서 사설 대역을 광고하는 방식으로 전환됩니다. 이는 하나의 VPS에서 한 번만 공지하고 중앙에서 승인하면 되므로, 모든 클라이언트 파일에 일일이 붙여넣을 필요가 없습니다. 이러한 전환이 가치 있는지는 호스팅된 제어 평면이 실제로 무엇에 접근할 수 있는지에 달려 있으며, 제어 평면은 트래픽을 암호화하는 키를 보유하지 않지만, 어떤 피어가 서로를 인식할지는 결정합니다.
이 모든 과정에는 사용자가 제어할 수 있는 Linux 서버, 공인 IP, 모듈을 로드할 수 있는 커널, 그리고 처음부터 끝까지 직접 관리하는 방화벽이 필요합니다.
FAQ
WireGuard 핸드셰이크가 완료되지 않는 이유는 무엇입니까?
wg show에서 피어 목록에 latest handshake이 표시되지 않는다면 패킷이 도착하지 않거나 수락되지 않는 상태입니다. VPS 방화벽과 제공업체의 별도 네트워크 방화벽에서 UDP 51820 포트를 확인하고, Endpoint 호스트와 포트가 정확한지 확인하십시오. 그 후 키가 서로 바뀌지 않았는지 확인하십시오. 클라이언트의 [Peer] 블록에는 반드시 서버의 공개 키가 포함되어야 합니다. 서버에서 sudo tcpdump -ni any udp port 51820을 실행하면 패킷이 실제로 도착하는지 확인할 수 있습니다. dmesg는 동적 디버그(echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control)를 활성화한 후에만 WireGuard의 핸드셰이크 실패를 보고하며, 이때 키 불일치는 invalid-MAC 드롭으로 나타납니다.
터널은 연결되는데 인터넷이 되지 않습니다. 무엇이 문제입니까?
ping 10.8.0.1는 작동하는데 ping 1.1.1.1에서 타임아웃이 발생한다면 포워딩이나 NAT 설정 문제입니다. sysctl net.ipv4.ip_forward 값이 1인지 확인하고, 재부팅 시 사라지는 sysctl -w 명령어가 아니라 /etc/sysctl.d/에 설정되어 있는지 확인하십시오. 그 후 ip route show default, enp1s0, ens3(드물게 eth0)에서 실제 외부 인터페이스 이름을 확인하여 매스커레이드(masquerade) 규칙을 설정하십시오.
클라이언트 설정에 DNS = 줄이 꼭 필요한가요?
전체 터널을 사용하면서 DNS = 줄이 없으면, 클라이언트는 로컬 네트워크에서 학습한 리졸버를 그대로 유지합니다. 이 경우 다른 모든 트래픽은 터널링되지만 DNS 쿼리는 로컬 링크를 통해 평문으로 전송됩니다. DNS을 공개 리졸버로 지정하거나, 10.8.0.1에 바인딩된 unbound/dnsmasq을 실행하고 입력 체인에서 udp dport 53 iifname "wg0" 포트를 여십시오.
AllowedIPs은 정확히 어떤 역할을 합니까?
이 설정은 두 가지 작업을 수행합니다. 아웃바운드에서는 라우팅 테이블 역할을 하여, 피어의 AllowedIPs와 일치하는 트래픽을 암호화한 뒤 해당 피어로 전송합니다. 인바운드에서는 접근 제어 목록(ACL) 역할을 하여, 복호화된 패킷의 발신지가 해당 피어의 AllowedIPs 범위를 벗어나면 패킷을 폐기합니다. 이것이 서버 측에서는 클라이언트마다 /32를 나열하고, 클라이언트 측에서는 0.0.0.0/0를 나열하는 이유입니다.
WireGuard는 모든 VPS에서 실행됩니까?
KVM VPS에서는 커널 내장 모듈을 사용하여 별도 설정 없이 작동합니다. OpenVZ나 LXC처럼 호스트 커널을 공유하는 컨테이너 가상화 환경에서는 modprobe wireguard이 Operation not supported 오류와 함께 실패하며, 이 경우 wireguard-go 사용자 공간 구현체를 사용해야 합니다. 다른 작업을 시작하기 전에 sudo modprobe wireguard && echo ok를 먼저 실행해 보십시오.