사설 클라우드 구축하기 - 2 (WireGuard)
Proxmox web이 외부로 노출되는 것을 막고, 안전하게 내부에서만 작업할 수 있도록 VPN을 뚫어주어야 한다.
이를 위해 WireGuard를 이용했다.
처음엔 wg-easy를 사용하려 했지만, AllowedIPs를 설정함에 있어서 편의성이 부족하여 WGDashboard로 갈아탔다.
기본적인 가이드라인은 다음 글을 참고했다.
https://svrforum.com/svr/43830
wg-easy 환경 설정
wget https://raw.githubusercontent.com/WeeJeWel/wg-easy/master/docker-compose.yml
위 yaml파일을 다운 받고, 글에 나온대로 WG_HOST, PASSWORD, ... 등을 설정하고 실행했더니
/app/lib/Server.js:311
throw new Error('DO NOT USE PASSWORD ENVIRONMENT VARIABLE. USE PASSWORD_HASH INSTEAD.\nSee https://github.com/wg-easy/wg-easy/blob/v14/How_to_generate_an_bcrypt_hash.md');
^
Error: DO NOT USE PASSWORD ENVIRONMENT VARIABLE. USE PASSWORD_HASH INSTEAD.
See https://github.com/wg-easy/wg-easy/blob/v14/How_to_generate_an_bcrypt_hash.md
at new Server (/app/lib/Server.js:311:13)
at Object.<anonymous> (/app/services/Server.js:5:18)
at Module._compile (node:internal/modules/cjs/loader:1730:14)
at Object..js (node:internal/modules/cjs/loader:1895:10)
at Module.load (node:internal/modules/cjs/loader:1465:32)
at Function._load (node:internal/modules/cjs/loader:1282:12)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)
at Module.require (node:internal/modules/cjs/loader:1487:12)
at require (node:internal/modules/helpers:135:16)
위 에러가 계속 뜨면서 서버가 올라가지 않았다.
에러 내용은 환경 변수중에 PASSWORD대신 PASSWORD_HASH를 사용하라는 것이었고, 이 해시된 암호는 bcrypt를 사용해야한다는 의미였다.
그래서 아래와 같이 바꿔줬다.
version: "3.8"
services:
wg-easy:
environment:
# Required:
# Change this to your host's public address
- WG_HOST=VPN공인IP
- PASSWORD_HASH=Bcrypt 처리된 암호
- WG_PORT=51820
- WG_DEFAULT_ADDRESS=10.255.255.x
- WG_DEFAULT_DNS=1.1.1.1
- WG_ALLOWED_IPS=0.0.0.0/0, ::/0
# Optional:
# - PASSWORD=foobar123
# - WG_PORT=51820
# - WG_DEFAULT_ADDRESS=10.8.0.x
# - WG_DEFAULT_DNS=1.1.1.1
# - WG_MTU=1420
# - WG_ALLOWED_IPS=192.168.15.0/24, 10.0.1.0/24
# - WG_PRE_UP=echo "Pre Up" > /etc/wireguard/pre-up.txt
# - WG_POST_UP=echo "Post Up" > /etc/wireguard/post-up.txt
# - WG_PRE_DOWN=echo "Pre Down" > /etc/wireguard/pre-down.txt
# - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt
image: ghcr.io/wg-easy/wg-easy
container_name: wg-easy
volumes:
- .:/etc/wireguard
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
그랬더니 이제는
ERROR: Invalid interpolation format for "environment" option in service "wg-easy": "PASSWORD_HASH=Bcrypt처리된 비밀번호"
위와 같이 유효하지 않은 포맷이라고 에러를 뱉어냈다..
GPT에 물어보니 \$ 표시를 환경변수 이름으로 착각하여 파싱 오류가 발생한다고 한다.
해결하기 위해 GPT가 시키는대로 큰따옴표로 감싸보고 작은따옴표로 감싸보고 그랬는데도 여전히 오류가 나서 그냥 환경변수화 시켜버렸다.
.env파일을 docker-compose.yml과 같은 디렉토리에 위치시키고
root@WG:~# cat .env
WG_HOST=공인IP주소
PASSWORD_HASH=bcrypt 처리된 비밀번호
WG_PORT=51820
WG_DEFAULT_ADDRESS=10.255.255.x
WG_DEFAULT_DNS=1.1.1.1
WG_ALLOWED_IPS=0.0.0.0/0, ::/0
이와 같이 작성한 후,
docker-compose.yml 내용을 아래와 같이 변경했다.
root@WG:~# cat docker-compose.yml
version: "3.8"
services:
wg-easy:
environment:
# Change this to your host's public address
- WG_HOST=${WG_HOST}
- PASSWORD_HASH=${PASSWORD_HASH}
- WG_PORT=${WG_PORT}
- WG_DEFAULT_ADDRESS=${WG_DEFAULT_ADDRESS}
- WG_DEFAULT_DNS=${WG_DEFAULT_DNS}
- WG_ALLOWED_IPS=${WG_ALLOWED_IPS}
...이하 생략
이렇게 바꾸고 다시 실행해보니 정상적으로 동작했다.
(뒤늦게 찾아보니 \$대신 \$\$처럼 쓰면 된다고 한다 https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1720#issuecomment-1004045902)
Invalid interpolation format when using docker-compose · Issue #1720 · NginxProxyManager/nginx-proxy-manager
hi there os: latest version of debian 11 mariadb: latest version 10.6 direct from mariadb apt repo docker: latest version from docker.io apt repo then i executed "mysql_secure_installation" and set...
github.com
그리고 VPN을 이용하면 데이터 송수신이 가능하도록 Proxmox 호스트에 포트 포워딩을 통해 51820 UDP는 192.168.0.2로 보냈다.
iptables -t nat -A PREROUTING -p udp --dport 51820 -j DNAT --to-destination 192.168.0.2:51820
전체 VPN 통신 흐름을 그려보면 아래와 같다.
[클라이언트] --인터넷--> [Proxmox Host]
│
DNAT (51820/udp to 192.168.0.2:51820)
↓
[LXC WG 컨테이너 (192.168.0.2)]
↓
Docker (wg-easy) → 내부 wg0: 10.255.255.1
테스트
아래는 http://192.168.0.2(내부망주소):51821/ 을 치고 들어가 클라이언트를 하나 추가한 모습이다.

테스트를 위해 핸드폰에 WireGuard 어플을 깔고 QR코드를 이용해 등록했다.

그다음에 Proxmox web이 들어가지는지 확인.

LTE 환경에서 잘 접속되는 모습이다.
WGDashboard
wg-easy는 내 니즈를 다 받아주지 못했다.
VPN에 접속하는 유저에 따라 내부망에서 어디까지 접근할 수 있을지 제한을 두어야 하는데, wg-easy는 직접 터미널에 들어가 일일이 AllowedIPs를 수정해주어야 한다.
그래서 이를 더 간편하게 해줄 수 있는 도구를 찾다가 최신까지 업데이트가 진행중인 WGDashboard를 발견했다.
https://github.com/donaldzou/WGDashboard/tree/main/docker
WGDashboard/docker at main · donaldzou/WGDashboard
Simple dashboard for WireGuard VPN written in Python & Vue.js - donaldzou/WGDashboard
github.com
여기에 나온 docker compose 파일을 참고했다.
version: '3.8'
services:
wgdashboard:
image: donaldzou/wgdashboard:latest
container_name: wgdashboard
restart: unless-stopped
environment:
- tz=Asia/Seoul
- public_ip=공인IP
- global_dns=1.1.1.1
ports:
- "10086:10086"
- "51820:51820/udp"
volumes:
- ./conf:/etc/wireguard
- ./data:/data
cap_add:
- NET_ADMIN
그런후 'docker-compose up -d' 로 실행시킨 후, http://아이피주소:10086/ 로 접속하면 된다. 해당 페이지 또한 외부로 노출되면 좋지 않으니 내부망에서만 작업하는게 좋다.
초기 아이디/비밀번호는 admin/admin이다.

대시보드에서 여러 와이어가드를 설정할 수 있고,
각 피어마다 설정을 더 자세하게 할 수 있다.

Endpoint Allowed IPs에 내부에 접근 가능한 IP들을 나열하면 된다.
후기
vpn을 구축하면서 많은 네트워크 설정을 건드려 보았다...
포트포워딩, NAT, 방화벽...
계속 안되는 부분이 있어서 한참을 해맸던 것 같다. 그 과정 속에서 많은 고민을 하고, 트래픽 흐름도 생각해보고..
결국 원하는 결과를 얻었으니 만족한다.
와이어가드 참 좋은 것 같다. 속도도 빠르고, 터널링을 함에 있어 여러 OS도 지원해준다. 굳!
다음은 NPM(Nginx Proxy Manager)를 이용해 Reverse proxy 컨트롤을 하려 한다.
'개발 > 프로젝트 로그' 카테고리의 다른 글
| JetBrains IDE 백준 플러그인 BOJ Helper 개발 (0) | 2026.03.02 |
|---|---|
| 나만의 티스토리 블로그 스킨 제작기 (0) | 2026.01.02 |
| [프로젝트 회고] 당일 남는 음식을 싸게 구매할 수 있는 서비스 (12) | 2025.08.25 |
| 사설 클라우드 구축하기 - 1 (1) | 2025.06.29 |
| [프로젝트 회고] 실시간 여행 계획 협업 웹앱 (2) | 2025.06.06 |