On-Demand Apache Guacamole + Cloudflare Tunnel을 이용한 Mac Mini 웹 원격 데스크톱 시스템
웹 브라우저만으로 어디서나 Mac Mini에 접속할 수 있는 시스템입니다. 접속 요청 시 자동으로 서비스를 시작하고, 유휴 시간 이후 자동으로 종료합니다.
┌─────────────────────────────────────────────────────────────────────┐
│ Mac Mini (M4, macOS) │
│ │
│ ┌──────────────┐ ┌─────────────────────────────────────────┐ │
│ │ CF Tunnel │ │ Docker Compose Stack │ │
│ │ (cloudflared│ │ ┌──────────┐ ┌─────────────────┐ │ │
│ │ :7844) │ │ │ guacd │ │ postgres:16 │ │ │
│ └──────┬───────┘ │ │ (4822) │ │ (5432) │ │ │
│ │ │ └────┬─────┘ └────────┬────────┘ │ │
│ ▼ │ │ │ │ │
│ ┌──────────────┐ │ ┌────┴──────────────────────┴───────┐ │ │
│ │ Gatekeeper │───▶│ │ guacamole web (:8080) │ │ │
│ │ (:8888) │ │ └──────────────────────────────────┘ │ │
│ │ [launchd] │ └─────────────────────────────────────────┘ │
│ └──────────────┘ │ │
│ │ ▼ │
│ └──── 30분 idle ─────▶ docker compose down │
│ │
│ VNC Server (:5900) │
│ [macOS 화면 공유] │
└─────────────────────────────────────────────────────────────────────┘
▲
│ HTTPS (CF Access 인증)
│
┌────────┴───────────┐
│ 웹 브라우저 │
│ remote.parallelai.work │
└────────────────────┘
1. 브라우저 → https://remote.parallelai.work
2. CF Access 인증 (Google/GitHub OAuth)
3. CF Tunnel → localhost:8888 (Gatekeeper)
4. Gatekeeper: 스택 down → docker compose up -d 실행
5. 로딩 페이지 표시 (5초마다 자동 새로고침)
6. Guacamole(:8080) 준비 완료 → 302 Redirect
7. Guacamole 로그인 → VNC(:5900) 연결
8. 30분 무활동 → docker compose down (자동 절전)
| 항목 | 요구사항 |
|---|---|
| macOS | 13 Ventura 이상 (M-series 권장) |
| Docker | Docker Desktop 4.x 또는 OrbStack 1.x |
| Docker Compose | v2.x (docker compose) |
| Python | 3.10 이상 (/usr/bin/python3) |
| 인터넷 연결 | Cloudflare Tunnel용 아웃바운드 연결 필요 |
mac-remote-access/
├── docker-compose.yml # Guacamole 스택 정의
├── init/
│ └── initdb.sql # PostgreSQL 초기 스키마 + 데이터
├── gatekeeper/
│ ├── main.py # On-demand 게이트키퍼 서버
│ └── requirements.txt # Python 의존성 (aiohttp)
├── launchd/
│ └── com.byl.mac-remote-gatekeeper.plist # macOS 서비스 정의
├── cloudflare/
│ └── tunnel-config.json # CF Tunnel 설정 참고용
├── scripts/
│ ├── install.sh # 전체 설치 스크립트
│ └── setup-vnc.sh # VNC 설정 스크립트
├── data/
│ ├── postgres/ # PostgreSQL 데이터 (git ignored)
│ └── guacamole/ # Guacamole 데이터 (git ignored)
└── README.md
git clone https://github.com/hochizo5940/mac-remote-access ~/mac-remote-access
cd ~/mac-remote-access# 화면 공유 서비스 활성화 및 비밀번호 설정
sudo ./scripts/setup-vnc.sh "your_vnc_password_here"또는 수동으로:
시스템 설정→일반→공유화면 공유활성화 (ON)정보(i)클릭 →원격 사용자 가상 네트워크 컴퓨팅 (VNC) 뷰어가 화면을 제어하도록 허용체크비밀번호 설정클릭 → 비밀번호 입력
init/initdb.sql에서 VNC 비밀번호 파라미터를 추가합니다:
-- initdb.sql 마지막 부분에 추가
INSERT INTO guacamole_connection_parameter (connection_id, parameter_name, parameter_value)
SELECT connection_id, 'password', 'your_vnc_password_here'
FROM guacamole_connection WHERE connection_name = 'Mac Mini VNC';
⚠️ 주의: PostgreSQL 데이터가 이미 초기화된 경우,data/postgres디렉토리를 삭제하고 재시작해야 합니다.
./scripts/install.sh이 스크립트는 자동으로:
- 필요한 디렉토리 생성 (
data/postgres,data/guacamole) - Python 패키지 설치 (
aiohttp) - launchd 서비스 등록 및 시작
자동 설치 대신 수동으로 진행할 수 있습니다:
# 디렉토리 생성
mkdir -p data/postgres data/guacamole
# Python 패키지 설치
pip3 install -r gatekeeper/requirements.txt --user
# launchd plist 복사 및 경로 수정
cp launchd/com.byl.mac-remote-gatekeeper.plist ~/Library/LaunchAgents/
# /Users/byl/mac-remote-access 경로를 실제 경로로 변경
nano ~/Library/LaunchAgents/com.byl.mac-remote-gatekeeper.plist
# 서비스 로드
launchctl load ~/Library/LaunchAgents/com.byl.mac-remote-gatekeeper.plistcloudflare-infra-gitops 레포의 tunnel.tf에 다음을 추가합니다:
# tunnel.tf
resource "cloudflare_tunnel_config" "parallelai" {
# ... 기존 설정 ...
config {
# ... 기존 ingress rules ...
# Mac Mini Remote Access 추가
ingress_rule {
hostname = "remote.parallelai.work"
service = "http://localhost:8888"
}
# 기존 catch-all은 마지막에 유지
ingress_rule {
service = "http_status:404"
}
}
}resource "cloudflare_record" "remote" {
zone_id = var.zone_id
name = "remote"
value = "${var.tunnel_id}.cfargotunnel.com"
type = "CNAME"
proxied = true
}Terraform 적용:
cd ~/cloudflare-infra-gitops
terraform plan
terraform apply중요:
remote.parallelai.work는 반드시 CF Access로 보호해야 합니다.
- Cloudflare Zero Trust 접속
Access→Applications→Add an application- 설정:
- Type: Self-hosted
- Application name:
Mac Mini Remote Access - Application domain:
remote.parallelai.work - Session Duration:
24 hours
Policy추가:- Policy name:
Allow parallelai.work users - Action: Allow
- Include: Email domain →
parallelai.work
- Policy name:
- Save
resource "cloudflare_access_application" "remote" {
zone_id = var.zone_id
name = "Mac Mini Remote Access"
domain = "remote.parallelai.work"
session_duration = "24h"
cors_headers {
allowed_methods = ["GET", "POST"]
allow_credentials = true
}
}
resource "cloudflare_access_policy" "remote_allow" {
application_id = cloudflare_access_application.remote.id
zone_id = var.zone_id
name = "Allow parallelai.work"
precedence = 1
decision = "allow"
include {
email_domain = ["parallelai.work"]
}
}Guacamole에는 TOTP(Time-based One-Time Password) 2단계 인증이 내장되어 있습니다.
docker-compose.yml에 이미 설정되어 있습니다:
environment:
TOTP_ENABLED: "true"- Guacamole에 로그인 (
admin/changeme123!) - 우측 상단 사용자 메뉴 →
설정 계정탭 →TOTP 인증 설정- QR 코드를 Google Authenticator / Authy 등으로 스캔
- 인증 코드 입력하여 확인
TOTP가 작동하지 않으면 확장 파일을 수동으로 설치합니다:
# Guacamole 컨테이너에서
docker exec -it guacamole bash
# TOTP 확장 다운로드
wget https://downloads.apache.org/guacamole/1.5.5/binary/guacamole-auth-totp-1.5.5.tar.gz
tar xzf guacamole-auth-totp-1.5.5.tar.gz
cp guacamole-auth-totp-1.5.5/guacamole-auth-totp-1.5.5.jar \
/etc/guacamole/extensions/- URL:
http://localhost:8080/guacamole/(직접 접속) - 또는:
http://localhost:8888(Gatekeeper 경유) - 사용자:
admin - 비밀번호:
changeme123!
⚠️ 반드시 첫 로그인 후 비밀번호를 변경하세요!
- 로그인 후 우측 상단
admin클릭 설정→계정탭- 새 비밀번호 입력 및 저장
- Guacamole 관리자 메뉴 →
설정→연결 Mac Mini VNC클릭편집→ 필요한 설정 변경 (비밀번호, 해상도 등)저장
# 서비스 상태 확인
launchctl list com.byl.mac-remote-gatekeeper
# 서비스 시작
launchctl load ~/Library/LaunchAgents/com.byl.mac-remote-gatekeeper.plist
# 서비스 중지
launchctl unload ~/Library/LaunchAgents/com.byl.mac-remote-gatekeeper.plist
# 서비스 재시작
launchctl unload ~/Library/LaunchAgents/com.byl.mac-remote-gatekeeper.plist
launchctl load ~/Library/LaunchAgents/com.byl.mac-remote-gatekeeper.plist
# 로그 실시간 확인
tail -f ~/Library/Logs/mac-remote-gatekeeper.logcd ~/mac-remote-access
# 스택 시작
docker compose up -d
# 스택 중지
docker compose down
# 스택 상태 확인
docker compose ps
# 로그 확인
docker compose logs -f
# Guacamole 로그만
docker compose logs -f guacamole
# PostgreSQL 로그만
docker compose logs -f postgres
# 스택 재빌드 (이미지 업데이트)
docker compose pull
docker compose up -d# 헬스 체크
curl http://localhost:8888/health
# 상세 상태
curl http://localhost:8888/status
# 응답 예시
{
"status": "ok",
"guacamole": "up", # "up" | "down" | "starting"
"idle_seconds": 125.3
}# PostgreSQL 접속
docker compose exec postgres psql -U guacamole_user -d guacamole_db
# 사용자 목록 확인
SELECT name, disabled FROM guacamole_entity WHERE type='USER';
# 연결 목록 확인
SELECT connection_name, protocol FROM guacamole_connection;
# DB 초기화 (주의: 모든 데이터 삭제됨)
docker compose down
rm -rf data/postgres/*
docker compose up -d# 로그 확인
tail -50 ~/Library/Logs/mac-remote-gatekeeper.log
# Python 패키지 확인
python3 -c "import aiohttp; print(aiohttp.__version__)"
# 수동 실행 테스트
cd ~/mac-remote-access/gatekeeper
COMPOSE_FILE=../docker-compose.yml python3 main.py# Docker 상태 확인
docker compose ps
# 포트 확인
curl -I http://localhost:8080/guacamole/
# Guacamole 로그 확인
docker compose logs guacamole | tail -50
# PostgreSQL 연결 확인
docker compose logs postgres | tail -20# VNC 서버 상태 확인
lsof -iTCP:5900 -sTCP:LISTEN
# 화면 공유 서비스 상태
launchctl list com.apple.screensharing
# 재활성화
sudo launchctl kickstart -k system/com.apple.screensharing
# 방화벽 확인
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate# 이미지 플랫폼 확인
docker inspect guacamole/guacamole:1.5.5 | grep -i arch
# 강제로 ARM64 이미지 pull
docker pull --platform linux/arm64 guacamole/guacamole:1.5.5
docker pull --platform linux/arm64 guacamole/guacd:1.5.5
docker pull --platform linux/arm64 postgres:16-alpine# 데이터 디렉토리 초기화
docker compose down
rm -rf data/postgres/*
mkdir -p data/postgres
# 다시 시작
docker compose up -d
# 초기화 로그 확인
docker compose logs postgres# cloudflared 상태 확인
launchctl list com.cloudflare.cloudflared 2>/dev/null || \
ps aux | grep cloudflared
# Tunnel 상태 확인 (cloudflared가 설치된 경우)
cloudflared tunnel info ddcea241-300e-4533-8320-65cecc0acd54
# 로컬 Gatekeeper 직접 테스트
curl http://localhost:8888/health# 절전 설정 재적용
sudo pmset -a sleep 0 disksleep 0 displaysleep 0
# 현재 설정 확인
pmset -g| 항목 | 상태 | 조치 |
|---|---|---|
| CF Access 인증 | ✅ 필수 | Zero Trust 앱 설정 필요 |
| Guacamole 기본 비밀번호 | 첫 로그인 후 즉시 변경 | |
| TOTP 2FA | ✅ 활성화됨 | 사용자별 등록 필요 |
| VNC 비밀번호 | setup-vnc.sh로 설정 | |
| Guacamole 포트 노출 | ✅ 127.0.0.1만 | 외부 직접 접속 불가 |
| DB 비밀번호 | docker-compose.yml 수정 | |
| HTTPS | ✅ CF Tunnel | 종단간 암호화 |
| 항목 | 값 |
|---|---|
| Mac Mini | Apple Silicon M4 |
| macOS | 26.2 |
| Docker | 29.3.0 |
| CF Account ID | b1f0946e7212bdc6f330de8c40f13b96 |
| CF Tunnel ID | ddcea241-300e-4533-8320-65cecc0acd54 |
| CF Tunnel Name | parallelai-tunnel |
| Remote URL | https://remote.parallelai.work |
MIT License — Apache Guacamole는 Apache License 2.0