이 글의 목적은 자체 기업위챗 앱에 고정된 API 전달 진입점을 마련하는 것입니다. 호출자가 자신의 도메인으로 요청하면 Caddy가 qyapi.weixin.qq.com으로 전달합니다. 기업위챗 로그인을 대체하는 방법이 아니며, 앱 권한이나 기업 관리 콘솔의 접근 제한을 우회하지도 않습니다.

설명 이미지: 기업위챗 API 전달 — 업스트림 고정, 호출자 제한
도메인과 서버 준비
기업위챗 API에 접근할 수 있는 서버를 준비하고, 자신의 도메인을 그 서버로 연결합니다. 이 글에서는 wecom.example.com을 자리 표시자로 사용하며, 배포할 때는 반드시 실제 도메인으로 바꿔야 합니다. 서버의 실제 아웃바운드 IP도 기업 관리 콘솔의 관련 제한과 함께 확인해야 합니다. 해외 서버만 써야 하는 것은 아닙니다.
공용 진입점은 HTTPS를 사용합니다. Caddy가 인증서를 자동 발급받으려면 도메인 연결과 해당 검증 포트가 정상이어야 하며, access_token이 포함된 호출을 편하다는 이유로 평문 HTTP에 태워서는 안 됩니다.
Caddyfile
아래 설정은 하나의 고정된 호출자 공인 IP만 허용합니다. 198.51.100.10은 문서용 예시 주소이므로 반드시 교체해야 하며, 그대로 쓰면 안 됩니다.
wecom.example.com {
@allowed remote_ip 198.51.100.10
handle @allowed {
reverse_proxy https://qyapi.weixin.qq.com {
header_up Host {upstream_hostport}
}
}
handle {
respond "Forbidden" 403
}
}
이 설정은 업스트림을 고정한 것이지, 클라이언트가 임의로 대상을 지정할 수 있는 오픈 프록시가 아닙니다. 허용 목록은 Caddy가 실제로 보는 출발지 IP를 기준으로 매칭됩니다. 진입점 앞에 CDN이나 다른 프록시가 있다면 그 IP를 실제 클라이언트 주소로 그대로 간주할 수 없으므로, 신뢰할 수 있는 프록시 체인을 별도로 설계해야 합니다.
header_up Host {upstream_hostport}는 모든 버전에서 반드시 필요한 고정 표기는 아닙니다. 현재 Caddy 2.11부터는 HTTPS 업스트림에 대해 Host를 자동으로 처리합니다. 여기서 명시한 것은 요청 관계를 설명하고 호환 설정을 보여주기 위한 것이니, 명시적 Host 설정을 모든 버전의 요구 사항으로 받아들이지 마세요.
공식 Caddy 이미지로 실행하기
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
먼저 실제 Caddyfile을 준비한 다음 설정을 검사합니다.
docker compose run --rm caddy caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
docker compose up -d
docker compose logs --tail=100 caddy
htnanako/wxproxy는 또 다른 서드파티 프록시 컨테이너이며 공식 Caddy 이미지가 아닙니다. 둘은 서로 다른 배포 방식이므로 하나의 서비스로 섞어 쓰면 안 됩니다.
앱 연동 시에는 API 베이스 주소만 교체
앱이 원래 https://qyapi.weixin.qq.com/cgi-bin/...을 요청한다면, 커스텀 기업위챗 API 주소를 지원한다는 전제하에 https://wecom.example.com/cgi-bin/...으로 바꿉니다. 경로와 비즈니스 파라미터는 여전히 기업위챗 인터페이스 요구 사항에 맞춰 작성합니다.
기업위챗 secret, access_token, 메시지 본문을 공개 예시에 적지 마세요. 요청 로그를 켜기 전에 쿼리 문자열에 담긴 토큰을 먼저 고려하고, 트러블슈팅 스크린샷에서도 가려야 합니다. 실제 자격 증명이 없는 요청으로 출처 제한을 먼저 확인한 뒤, 자신의 환경에서 권한이 있는 인터페이스 테스트를 마치세요.
Discord의 초대 링크는 Webhook이 아닙니다. 연동 방식이 서로 다르므로 초대 주소를 메시지 API로 쓸 수 없습니다.
참고: Caddy 설치, reverse_proxy, 기업위챗 개발자 문서. 이 글은 문서와 설정 구조를 검토한 것으로, 여러분의 서버에 실제로 배포하거나 메시지를 보내지는 않았습니다.