공개 URL을 설정하여 내 사무실 조명을 깜빡이게 하기
I’m happy to translate the article for you, but I’ll need the full text of the post in order to do so. Could you please paste the content you’d like translated (excluding the source link you’ve already provided)? Once I have the article text, I’ll translate it into Korean while preserving the original formatting, markdown, and any code blocks or URLs.
문제
내 라즈베리 파이는 집 라우터 뒤에 있습니다. 포트 포워딩을 하거나 Home Assistant를 직접 노출하고 싶지는 않지만, 인터넷에서 트리거하고 싶습니다. Droplet이 이를 해결합니다—공개적으로 접근 가능합니다. 질문은: Droplet에서 내 파이로 안전하게 연결하려면 어떻게 해야 할까요?
솔루션: Tailscale
Tailscale은 장치들 간에 메쉬 VPN을 생성합니다. Droplet과 Pi 모두에 설치하면, 두 장치는 사설 IP(100.x.x.x와 같은)를 사용해 서로 통신할 수 있습니다—포트 포워딩이 필요 없습니다.
Internet → Droplet (public) → Tailscale → Pi (private) → Home Assistant
Source: https://example.com (원본 링크는 그대로 유지)
Claude Code가 만든 것
나는 Claude Code를 사용해 이 작업을 연결했다. 핵심 통찰은 Claude Code에 내 Pi와 droplet에 대한 SSH 접근 권한을 부여하고 나머지는 대부분 자동으로 처리하도록 할 수 있다는 것이었다.
그 결과:
- Pi에 SSH로 접속해 Home Assistant를 조회해 내 조명 엔티티 ID를 찾음
- 조명을 빨간색으로 깜빡인 뒤 이전 색상으로 복원하는 bash 스크립트를 작성함
- Pi와 droplet 모두에 Tailscale을 설치함
- droplet이 Pi에서 명령을 실행할 수 있도록 SSH 키를 생성함
- 토큰 기반 인증이 포함된 Flask 웹훅을 만들음
- 요청을 라우팅하도록 nginx를 설정함
- 모든 것이 재부팅 후에도 살아 있도록 systemd 서비스를 생성함
전체 작업은 약 20분 정도 걸렸다. 대부분은 apt가 패키지를 설치하는 동안 기다리는 시간이었는다.
아키텍처
Request: GET /flash-peter-office-lights?auth_token=xxx
↓
Cloudflare (HTTPS)
↓
DigitalOcean Droplet
nginx → Flask (port 5000)
↓
Tailscale (100.x.x.x)
↓
Raspberry Pi
SSH → flash_lights.sh
↓
Home Assistant API
↓
Lights flash red → restore
플래시 스크립트
조명을 이전 상태로 복원하는 것이 까다로운 부분입니다. Home Assistant 조명은 다양한 색상 모드가 있을 수 있기 때문에, 스크립트는 플래시하기 전에 현재 상태를 저장합니다:
# Save current state
STATE=$(curl -s -H "Authorization: Bearer $HA_TOKEN" \
"http://localhost:8123/api/states/light.office")
WAS_ON=$(echo $STATE | jq -r '.state')
BRIGHTNESS=$(echo $STATE | jq -r '.attributes.brightness // 255')
XY_X=$(echo $STATE | jq -r '.attributes.xy_color[0] // empty')
XY_Y=$(echo $STATE | jq -r '.attributes.xy_color[1] // empty')
# Flash red
curl -s -X POST "http://localhost:8123/api/services/light/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-d '{"entity_id": "light.office", "rgb_color": [255, 0, 0], "brightness": 255}'
sleep 1
# Restore
curl -s -X POST "http://localhost:8123/api/services/light/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-d "{\"entity_id\": \"light.office\", \"brightness\": $BRIGHTNESS, \"xy_color\": [$XY_X, $XY_Y]}"
첫 번째 버전은 밝기만 저장했습니다. 제가 Claude Code에게 “조명이 원래 상태로 돌아가지 않는다”고 말했을 때, xy_color 처리를 추가했습니다.
웹훅 (Flask)
from flask import Flask, request, jsonify
import subprocess
import json
app = Flask(__name__)
def load_tokens():
with open('/root/webhooks/tokens.json') as f:
return json.load(f)
@app.route('/flash-peter-office-lights')
def flash():
token = request.args.get('auth_token')
if not token:
return jsonify({"error": "Missing auth_token"}), 401
tokens = load_tokens()
if token not in tokens:
return jsonify({"error": "Invalid token"}), 403
# SSH to Pi via Tailscale and run the flash script
cmd = 'ssh -i /root/.ssh/pi_key peter@100.x.x.x "/home/peter/flash_lights.sh"'
subprocess.run(cmd, shell=True, timeout=15)
return jsonify({"status": "flashed", "user": tokens[token]["name"]})
토큰은 JSON 파일에 저장됩니다:
{
"alice-token-123": {"name": "Alice", "created": "2026-01-05"},
"bob-token-456": {"name": "Bob", "created": "2026-01-05"}
}
각 사용자에게 고유 토큰이 부여됩니다. 해당 항목을 삭제하면 접근 권한이 취소됩니다.
다음 단계
이제 파이프라인이 구축되었으니, 나는 다음을 할 수 있습니다:
- 다른 출처에 따라 다른 색상 – Slack은 파란색, 가족 문자 메시지는 초록색, 긴급 상황은 빨간색
- Slack 슬래시 명령 – 동료들을 위한
/flash-peter - iOS 단축키 – 아내를 위한 원터치 버튼
- 속도 제한 – 남용 방지
- 로그 기록 – 누가 언제 플래시했는지
비슷한 것을 만들고 싶다면, 필요한 요소는 다음과 같습니다: Raspberry Pi(또는 Home Assistant를 실행하는 다른 장치), 양쪽에 Tailscale이 설치된 저렴한 VPS, 그리고 기본적인 Python/Bash(제 경우에는 Claude가 작성함).