양쪽 콘솔 접근 수단과 VPN 밖의 기존 SSH 관리 세션
네트워크 · 구성 레시피
WireGuard 지점 간 VPN 구성
Ubuntu의 systemd-networkd와 WireGuard를 이용해 두 고정 지점 사이에 최소 범위 터널을 만들고, 개인키는 화면이나 명령 인자에 노출하지 않은 채 파일 참조로 안전하게 관리합니다.BEFORE YOU START
시작 전에 준비하세요
겹치지 않는 터널 주소 2개, 각 endpoint 주소·UDP 포트, 피어 공개키
허용할 대상 호스트를 /32로 확정한 라우팅 표와 방화벽 변경 계획
systemd-networkd가 현재 물리 NIC를 정상 관리한다는 확인과 네트워크 설정 백업
권장 대상 관리망 전체를 기본 경로로 우회하지 않고 특정 서버·지점 사이만 암호화하려는 인프라 운영자
FOLLOW THE RECIPE
8단계 구성·점검 레시피
커널·networkd·주소 체계 확인
이 가이드는 이미 동작 중인 systemd-networkd에 wg0 가상 인터페이스만 추가합니다. 다른 네트워크 관리자를 대체하거나 물리 NIC 구성을 바꾸지 않습니다.
cat /etc/os-release
uname -srsystemctl is-active systemd-networkd.service
networkctl listip -brief address
ip routemodinfo wireguard- systemd-networkd가 이미 active이고 현재 연결이 정상이다.
- 터널 주소가 로컬·원격 어느 네트워크와도 겹치지 않는다.
- VPN 밖의 콘솔·SSH 복구 경로가 있다.
NetworkManager만 사용하는 서버라면 이 파일을 적용하지 말고 NetworkManager의 공식 WireGuard 방식으로 별도 설계합니다.
기존 인터페이스·UDP 포트·라우팅 충돌을 점검합니다.
인터페이스·포트·경로 충돌 점검
wg0 이름과 수신 UDP 포트, 터널 주소 경로가 비어 있는지 확인합니다. AllowedIPs는 인증 대상이면서 라우팅 범위이므로 먼저 표로 승인받습니다.
ip link show wg0
sudo wg show wg0sudo ss -lunp | grep ':<WG_PORT> 'ip route get <PEER_TUNNEL_IPV4>
ip route show table all출력에 내부 주소가 포함될 수 있으므로 외부에 그대로 공유하지 않습니다.sudo find /etc/systemd/network -maxdepth 1 -type f -name '*wg0*' -print- wg0와 <WG_PORT>를 다른 서비스가 사용하지 않는다.
- <PEER_TUNNEL_IPV4>/32가 기존 LAN·클라우드·컨테이너 대역과 겹치지 않는다.
- 피어 공개키를 신뢰된 별도 채널로 확인했다.
겹치는 경로가 있으면 넓은 AllowedIPs로 덮지 말고 터널 주소 계획부터 변경합니다.
배포판 패키지를 검토하고 도구만 설치합니다.
WireGuard 도구 설치
커널 지원을 확인한 뒤 공식 Ubuntu 패키지에서 wireguard-tools를 설치합니다. 패키지 설치가 기존 네트워크 구성을 변경하지는 않습니다.
sudo apt updateapt-get --simulate install wireguard-toolssudo apt-get install wireguard-toolswg --version- 의도하지 않은 커널·네트워크 패키지 제거가 없다.
- wg 도구와 커널 모듈을 확인했다.
- 양쪽 지점의 지원되는 패키지 수명주기를 기록했다.
모듈을 찾지 못하면 임의 DKMS를 추가하기 전에 현재 커널과 Ubuntu 지원 상태를 확인합니다.
개인키 파일을 출력 없이 만들고 networkd 구성을 준비합니다.
개인키 파일과 최소 피어 경로 구성
개인키는 셸 인자·브라우저·URL에 넣지 않고 제한된 파일에 바로 생성합니다. 구성에는 키 값이 아니라 PrivateKeyFile 경로만 기록합니다.
date -u +%Y%m%dT%H%M%SZsudo install -d -m 0750 -o root -g systemd-network /etc/wireguardsudo sh -c 'umask 037; test ! -e /etc/wireguard/wg0.key && wg genkey > /etc/wireguard/wg0.key'이미 키 파일이 있으면 명령이 실패하며 덮어쓰지 않습니다. 개인키 내용을 cat·복사·스크린샷하지 않습니다.sudo chown root:systemd-network /etc/wireguard/wg0.key
sudo chmod 0640 /etc/wireguard/wg0.keysudo sh -c 'umask 022; wg pubkey < /etc/wireguard/wg0.key > /etc/wireguard/wg0.pub'sudo cp --preserve=all --no-clobber /etc/systemd/network/30-wg0.netdev /etc/systemd/network/30-wg0.netdev.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sudo cp --preserve=all --no-clobber /etc/systemd/network/30-wg0.network /etc/systemd/network/30-wg0.network.<BACKUP_SUFFIX>.bak기존 파일이 있을 때만 실행합니다.sudoedit /etc/systemd/network/30-wg0.netdevsudoedit /etc/systemd/network/30-wg0.network[NetDev]
Name=wg0
Kind=wireguard
Description=Restricted site-to-site WireGuard tunnel
[WireGuard]
PrivateKeyFile=/etc/wireguard/wg0.key
ListenPort=<WG_PORT>
[WireGuardPeer]
PublicKey=<PEER_PUBLIC_KEY>
AllowedIPs=<PEER_TUNNEL_IPV4>/32
Endpoint=<PEER_ENDPOINT_IP>:<PEER_WG_PORT>
PersistentKeepalive=25
RouteTable=mainAllowedIPs는 이 피어가 사용할 정확한 터널 호스트 /32만 넣습니다. 기본 경로나 전체 사설망을 넣으려면 별도 라우팅·접근통제 검토가 필요합니다.[Match]
Name=wg0
[Network]
Address=<SERVER_TUNNEL_IPV4>/32서버와 피어 주소는 서로 달라야 하며 기존 네트워크와 겹치지 않아야 합니다.- 개인키 값이 명령 인자·출력·설정 예시에 나타나지 않는다.
- 개인키 파일은 root:systemd-network 0640이다.
- AllowedIPs는 단일 피어 /32이며 기본 경로가 아니다.
- 피어 공개키와 endpoint를 별도 신뢰 채널로 대조했다.
PrivateKeyFile을 읽지 못하면 키를 설정 파일에 붙여넣지 말고 파일 소유권·그룹·systemd 버전을 확인합니다.
UDP 인바운드를 제한하고 networkd가 구성 파일을 읽도록 합니다.
제한 규칙 확인 후 인터페이스 반영
기존 관리 세션을 유지합니다. UFW가 이미 활성 상태일 때만 피어 endpoint 한 곳에서 오는 UDP를 허용하고 networkd를 reload합니다.
sudo ufw status numberedsudo ufw --dry-run allow proto udp from <PEER_ENDPOINT_IP> to <SERVER_LOCAL_LISTEN_IP> port <WG_PORT>sudo ufw allow proto udp from <PEER_ENDPOINT_IP> to <SERVER_LOCAL_LISTEN_IP> port <WG_PORT>UFW가 이미 active이고 SSH 및 콘솔 복구가 확인된 경우에만 실행합니다. 동적 endpoint라면 광범위 허용 대신 상위 VPN 게이트웨이 설계를 검토합니다.sudo chown root:systemd-network /etc/systemd/network/30-wg0.netdev
sudo chmod 0640 /etc/systemd/network/30-wg0.netdev
sudo chown root:root /etc/systemd/network/30-wg0.network
sudo chmod 0644 /etc/systemd/network/30-wg0.networksudo networkctl reload
sudo networkctl reconfigure wg0networkctl status wg0
sudo journalctl -u systemd-networkd.service -n 100 --no-pager- 방화벽은 한 피어 endpoint의 UDP만 허용한다.
- 물리 NIC의 기존 주소와 기본 경로는 바뀌지 않았다.
- wg0가 routable 또는 configured 상태다.
wg0가 failed면 networkd 로그에서 섹션 이름·권한·PrivateKeyFile 읽기 오류를 확인하고 물리 NIC 설정은 변경하지 않습니다.
공개키·handshake·/32 경로와 실제 통신을 검증합니다.
handshake와 최소 경로 검증
개인키를 보여주는 전체 구성 출력은 사용하지 않습니다. 공개 가능한 필드와 handshake 시간, 전송량, 정확한 /32 경로만 조회합니다.
sudo wg show wg0 public-key
sudo wg show wg0 listen-port
sudo wg show wg0 peers
sudo wg show wg0 latest-handshakes
sudo wg show wg0 transferip -brief address show wg0
ip route get <PEER_TUNNEL_IPV4>ping -c 3 <PEER_TUNNEL_IPV4>sudo ss -lunp | grep ':<WG_PORT> '
systemctl is-active systemd-networkd.service- latest-handshake가 현재 시각에 가깝고 전송·수신 바이트가 증가한다.
- 피어 터널 주소의 경로만 wg0를 사용한다.
- 기존 기본 경로와 SSH 관리 경로는 VPN 밖에 남아 있다.
handshake가 없으면 endpoint·UDP 방화벽·공개키를, handshake는 있지만 통신이 없으면 AllowedIPs·주소·피어 방화벽을 확인합니다.
키 보관·라우팅 범위·로그 노출을 최종 점검합니다.
키·라우팅·접근 범위 최종 점검
WireGuard 공개키 인증은 서비스 접근 권한을 대신하지 않습니다. 터널 안에서도 목적지 서비스 방화벽과 애플리케이션 인증을 유지합니다.
sudo stat -c '%U:%G %a %n' /etc/wireguard/wg0.key /etc/systemd/network/30-wg0.netdevip route show table mainsudo ufw status numberedsudo journalctl -u systemd-networkd.service --since '-30 minutes' --no-pager- 개인키를 백업·티켓·메신저·브라우저에 복사하지 않았다.
- AllowedIPs와 설치된 route가 승인한 /32보다 넓지 않다.
- UDP 포트는 승인한 endpoint에서만 도달할 수 있다.
- 터널 내부 서비스도 최소 포트·최소 권한으로 제한한다.
- 키 교체 절차와 피어 제거 절차를 양쪽 지점에 기록했다.
예상하지 못한 넓은 route가 있으면 통신을 확대하지 말고 해당 피어 구성을 롤백합니다.
필요하면 wg0 파일만 비활성화해 원래 네트워크를 보존합니다.
wg0 구성만 비활성화하고 복원
기본 경로와 물리 NIC를 건드리지 않고 wg0만 내립니다. 개인키는 삭제하지 않고 제한된 .disabled 파일로 보존해 사고 조사와 승인된 재사용에 대비합니다.
ip route get <ADMIN_CLIENT_IP>
who
networkctl status wg0sudo networkctl down wg0sudo mv /etc/systemd/network/30-wg0.netdev /etc/systemd/network/30-wg0.netdev.disabled.<ROLLBACK_SUFFIX>sudo mv /etc/systemd/network/30-wg0.network /etc/systemd/network/30-wg0.network.disabled.<ROLLBACK_SUFFIX>sudo cp --preserve=all /etc/systemd/network/30-wg0.netdev.<BACKUP_SUFFIX>.bak /etc/systemd/network/30-wg0.netdev작업 전 실제 백업이 있었던 경우에만 실행합니다.sudo cp --preserve=all /etc/systemd/network/30-wg0.network.<BACKUP_SUFFIX>.bak /etc/systemd/network/30-wg0.network작업 전 실제 백업이 있었던 경우에만 실행합니다.sudo networkctl reloadsudo ufw delete allow proto udp from <PEER_ENDPOINT_IP> to <SERVER_LOCAL_LISTEN_IP> port <WG_PORT>이번 작업이 추가한 정확한 규칙일 때만 제거합니다.sudo mv /etc/wireguard/wg0.key /etc/wireguard/wg0.key.disabled.<ROLLBACK_SUFFIX>
sudo chmod 0600 /etc/wireguard/wg0.key.disabled.<ROLLBACK_SUFFIX>- 콘솔 또는 VPN 밖 관리 세션에서 롤백했다.
- 물리 NIC와 기본 경로는 변경하지 않았다.
- 작업 전 백업이 있던 파일만 복원했다.
- 개인키는 화면에 출력하거나 평문 공유하지 않고 제한 보관했다.
wg0를 내려도 기존 SSH가 끊긴다면 관리 경로를 터널에 의존하도록 설계한 것입니다. 콘솔에서 복원하고 관리망 경계를 다시 설계합니다.
endpoint·키·AllowedIPs 중 실패 원인을 분리하고 양쪽 변경 기록을 맞춥니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- 개인키는 PrivateKeyFile로만 읽고 명령 인자·출력·URL에 넣지 않는다.
- AllowedIPs는 승인된 단일 피어 /32부터 시작한다.
- 기본 경로와 SSH 관리 경로를 첫 구성에서 터널로 바꾸지 않는다.
- UDP 인바운드는 가능한 경우 고정 endpoint 주소로 제한한다.
- 터널 내부 서비스에도 별도 방화벽과 애플리케이션 인증을 유지한다.
COMMON ERRORS
자주 막히는 지점
handshake가 생성되지 않음
- 증상
- latest-handshakes가 비어 있거나 0으로 표시됩니다.
- 가능한 원인
- endpoint·UDP 포트·방화벽·공개키 중 하나가 양쪽에서 일치하지 않을 수 있습니다.
- 확인 순서
- 개인키를 출력하지 말고 공개키·endpoint·UDP 리스닝·상위 보안그룹을 양쪽에서 순서대로 비교합니다.
handshake는 있지만 피어가 응답하지 않음
- 증상
- 전송량은 보이나 ping 또는 서비스 연결이 실패합니다.
- 가능한 원인
- AllowedIPs·터널 주소·반대편 return route 또는 내부 방화벽이 맞지 않을 수 있습니다.
- 확인 순서
- 양쪽 route get 결과와 /32 AllowedIPs를 비교하고 서비스 포트를 최소 범위로 허용합니다.
networkd가 개인키를 읽지 못함
- 증상
- 로그에 PrivateKeyFile 권한 또는 읽기 실패가 표시됩니다.
- 가능한 원인
- 파일 소유 그룹·권한이 잘못됐거나 PrivateKeyFile을 지원하지 않는 systemd 버전일 수 있습니다.
- 확인 순서
- 키 값을 설정에 붙여넣지 말고 root:systemd-network 0640과 systemd.netdev 지원 버전을 확인합니다.
PRIMARY REFERENCES
공식 문서
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.