왜 필요한가
앱 안의 웹뷰에서만 생기는 문제는 고치기가 번거롭습니다. 코드를 한 줄 고칠 때마다 개발 서버에 배포하고, 앱을 다시 열어 확인해야 하니까요.
Proxyman 의 Map Remote 를 쓰면 이 과정을 건너뛸 수 있습니다. 앱이 개발 서버 주소로 요청을 보내도, 그 요청을 내 컴퓨터에서 띄운 로컬 서버(localhost)로 돌려보내 주기 때문입니다. 코드를 저장하면 앱에서 바로 바뀐 화면을 볼 수 있습니다.
준비
- Proxyman 을 설치하고, 안내에 따라 Proxyman 인증서를 Mac 에 설치·신뢰합니다. 그래야 HTTPS 요청 내용을 볼 수 있습니다.
- 실제 휴대폰으로 확인하려면 휴대폰과 Mac 을 같은 Wi-Fi 에 두고, Proxyman 의 기기 연결 안내대로 휴대폰에 프록시와 인증서를 설정합니다.
- 로컬에서 서비스를 띄워 둡니다. 이 글에서는
http://localhost:3000에 떠 있다고 가정합니다.
Map Remote 규칙 만들기
- Proxyman 메뉴 막대에서 Tools → Map Remote… 를 엽니다.
- 왼쪽 아래 + 버튼으로 새 규칙을 추가합니다.
- 규칙을 채웁니다.
- Matching Rule — 가로챌 주소. 예:
app.dev.example.com(Use Wildcard, 하위 경로 포함) - Map To — 대신 응답할 곳. 로컬 서버는 대부분 HTTP 라서 Protocol
http, Hostlocalhost, Port3000 - Preserve Host in Header Fields — 켜 두면 원래 주소의 Host 헤더가 유지됩니다. 서버가 Host 로 무언가를 구분한다면 켭니다.
- 목록에서 쓸 규칙만 체크해서 켭니다. 이제 앱이나 브라우저에서 개발 서버 주소로 들어가면 로컬 서버가 응답합니다.
정규식으로 더 정확하게 고르기
와일드카드로는 부족할 때가 있습니다. 예를 들어 화면은 로컬 서버가 그리고, /api 로 시작하는 요청은 그대로 개발 서버로 보내고 싶을 때입니다. 이때는 Use Regex 를 고르고 아래처럼 씁니다.
^(?:http|https|wss):\/\/admin\.dev\.example\.com(?:\:\d{4})?(\/\b(?!api\/?).+?\b.*|\/?$)wss까지 넣으면 코드를 고치면 화면이 바로 바뀌는 연결(HMR 웹소켓)도 로컬 서버로 갑니다.(?!api\/?)가/api로 시작하는 주소를 빼 줍니다.
로컬 서버가 다른 API 를 부를 때
로컬 서버가 서버 쪽에서 다른 API 를 부르는 구조(서버 사이드 렌더링, 프록시 미들웨어 등)라면, 그 요청도 Proxyman 을 거쳐야 할 때가 있습니다. 이때 Unexpected token < in JSON 같은 에러가 나거나 요청이 시간 초과로 끝나면, 서버를 띄우는 터미널에 Proxyman 의 프록시·인증서 환경 변수를 넣어 줍니다.
set -a && source "$HOME/.proxyman/proxyman_env_automatic_setup.sh" && set +a이 파일은 Proxyman 의 Setup → Automatic Setup… 을 한 번 실행하면 만들어집니다. 최신 버전에서는 이 기능이 유료로 바뀌었으니, 파일이 없다면 직접 만들어도 됩니다. Node 서버라면 아래 정도면 충분합니다.
# ~/.proxyman/proxyman_env_automatic_setup.sh
export HTTP_PROXY="http://127.0.0.1:9090"
export HTTPS_PROXY="http://127.0.0.1:9090"
export http_proxy="http://127.0.0.1:9090"
export https_proxy="http://127.0.0.1:9090"
export NODE_EXTRA_CA_CERTS="$HOME/.proxyman/proxyman-ca.pem"
export SSL_CERT_FILE="$HOME/.proxyman/proxyman-ca.pem"
export NODE_OPTIONS="--require \"/Applications/Proxyman.app/Contents/Frameworks/ProxymanCore.framework/Versions/A/Resources/overrides/js/js.min.js\""- 터미널 탭이 여러 개라면, 이 명령을 실행한 그 터미널에서 서버를 띄워야 합니다.
- 매번 치기 번거로우면
package.json의 실행 스크립트에 넣어 두면 편합니다.
VPN 을 써야 하는 환경에서 함께 쓰기
재택근무처럼 사내 개발 서버에 VPN 으로만 들어갈 수 있는 환경이라면 문제가 하나 더 생깁니다. Mac 에서 일부 VPN 앱을 켜면, Proxyman 이 트래픽을 제대로 잡지 못합니다.
이럴 때는 VPN 을 Mac 이 아니라 Docker 컨테이너 안에서 붙이는 방법으로 우회할 수 있습니다. 컨테이너는 VPN 에 접속한 뒤 SOCKS 프록시를 열고, Proxyman 은 VPN 이 필요한 요청만 그 프록시로 보냅니다.
Proxyman (External Proxy) → localhost:1080 (SOCKS) → Docker 컨테이너 → VPN1. 컨테이너에서 VPN 붙이기
Fortinet SSL-VPN 이라면 제가 만들어 공개해 둔 docker-fortivpn-proxy 이미지를 쓰면 됩니다. 컨테이너가 VPN 에 접속한 뒤 socks5://localhost:1080 으로 프록시를 열어 줍니다. 다른 VPN 이라면 openconnect 기반의 비슷한 이미지를 쓰면 같은 방식으로 됩니다. (Docker Desktop 대신 Rancher Desktop 이나 Podman 을 써도 됩니다)
# ~/.vpn/config — 실제 값은 각자의 VPN 정보로
OPENCONNECT_URL=vpn.example.com:443
OPENCONNECT_USER=me@example.com
OPENCONNECT_PASSWORD=********
OPENCONNECT_OPTIONS=--protocol=fortinet --servercert pin-sha256:<서버 인증서 값>docker run \
-it \
-e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 \
-p 1080:1080 \
--rm \
--env-file="$HOME/.vpn/config" \
ghcr.io/chussum/fortivpn-proxy:1.3.0자주 쓴다면 이 명령을 셸 스크립트나 alias 로 만들어 두면 편합니다.
2. Proxyman 이 VPN 이 필요한 요청만 보내게 하기
- Tools → Proxy Settings → External Proxy Settings… 를 엽니다.
- SOCKS Proxy 를 켜고
localhost:1080을 넣습니다. - Inclusive List for External Proxies 에 VPN 이 필요한 도메인만 적습니다. 예:
*.internal.example.com, *.dev.example.com. 나머지 인터넷 요청은 VPN 을 거치지 않아서 느려지지 않습니다.
이렇게 해 두면 VPN 이 필요한 개발 서버에서도 앞의 Map Remote 를 그대로 쓸 수 있습니다. 사무실처럼 VPN 이 필요 없는 곳에서는 External Proxy 를 꺼 두세요.
자주 막히는 곳
- VPN 컨테이너가 접속하지 못할 때 — 접속 정보 파일의 값을 다시 확인하고, Proxyman 을 끈 상태에서 컨테이너를 먼저 띄워 봅니다.
- 스키마 동기화 같은 CLI 명령이 네트워크 에러를 낼 때 — 그 명령을 실행하는 터미널에서도 위의 환경 변수 명령을 먼저 실행합니다.
마치며
Map Remote 하나로 "배포하고, 앱 열고, 확인하고" 를 반복하던 시간이 "저장하고 확인하기" 로 줄어듭니다. VPN 이 끼는 환경도 컨테이너 하나로 풀 수 있으니, 웹뷰 작업이 잦다면 한 번 세팅해 두는 걸 추천합니다.