Streamlit 운영 대시보드 NAS 배포 — 단일 URL + Tailscale 자동 감지 #44
Labels
No labels
api
bug
chore
collector
decision-needed
docs
enhancement
feature
feedback-loop
frontend
infra
skill
test
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
xhh/financial-data-platform#44
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
#22 에서 Streamlit 3페이지 구현은 완료됐지만 NAS 배포 + 외부 접근 경로 는 의도적으로 스코프 밖으로 뺐다. 이 이슈에서 마무리.
인증 방향 결정
단일 URL (
stock-admin.xhhan.com) + 클라이언트 JS Tailscale 프로브. 외부 공개로 조회 페이지를 열고, Tailscale 이 켜져 있는 브라우저에 한해 Manual Trigger UI 가 자동 활성.아키텍처
Tailscale 프로브 원리
100.100.100.100에 리스닝. 브라우저에서fetch("http://100.100.100.100/", {mode: "no-cors", signal: AbortSignal.timeout(800)})로 짧은 시도.st.session_state에 저장. Manual Trigger 페이지가 이 값을 읽어st.stop()/ 정상 렌더 분기.왜 클라이언트 검사로 충분한가
UI 노출 여부는 편의성일 뿐, 실제 write 동작은 write API 키가 담당. 이 키는 컨테이너 env 에 없음 → 사이드바에서 직접 입력해야 하고, Tailscale 안 켜고 억지로 Manual Trigger 페이지를 띄워도 키가 없어 아무 동작 안 함. 서버 측 보안과 클라이언트 UX 가 분리되어 있어 스푸핑 내성 자체는 API 가 담당한다.
구현할 것
1) Streamlit 앱 코드 수정
utils/api.py—DEFAULT_READ_API_KEY환경변수 폴백. 사이드바에 키가 없고 env 에 read 키가 있으면 자동 사용.utils/tailscale_probe.py(신규) — Streamlitcomponents.v1.html로 JS 프로브 삽입. 결과를st.session_state["tailscale_on"]으로 저장. 재호출시 캐시.app.py— 사이드바에🔓 Tailscale 감지됨/🌐 공개 모드배지 표시.pages/6_Manual_Trigger.py— 페이지 상단에서st.session_state.get("tailscale_on")이 False 면 안내 문구 +st.stop(). True 면 기존 UI.session_statemock 으로 public/admin 분기 검증 (JS 동작 자체는 단위 테스트 대상 아님).2) Streamlit 컨테이너화
frontend/streamlit/Dockerfile— python:3.13-slim +uv sync+ streamlit.docker-compose.yml에streamlit서비스 추가.API_URL=http://api:8000,DEFAULT_READ_API_KEY=<Secrets 주입>.curl -fsS http://localhost:8501/_stcore/health.3) Traefik 라우팅 + Cloudflare
docker-compose.ymlstreamlit 서비스에 Traefik 라벨 추가.stock-admin.xhhan.com.traefik-public네트워크 조인.stock-admin.xhhan.com서비스 매핑 추가 (운영자 작업).stock-adminCNAME (운영자 작업).4) 최초 배포 플레이북
uv run python scripts/apikey.py create --name "streamlit-public" --scopes "read"→ 원문 키를 Forgejo Secrets (DEFAULT_READ_API_KEY) 등록docker compose up -d --build streamlithttps://stock-admin.xhhan.com: 사이드바에🌐 공개 모드, Manual Trigger 페이지 입장 시 차단 문구🔓 Tailscale 감지됨, Manual Trigger 정상 렌더. write 키 입력 후 버튼 동작 확인완료 기준
stock-admin.xhhan.com단일 URL스푸핑 / 우회 시나리오 정리
tailscale_on=true를 JS 로 강제apikey.py rotate로 회전선행
참고
/api/health는 #14 에서 503 반환하도록 수정됨 → compose healthcheck 자동 감지api서비스 Runner (nas라벨) 재사용Streamlit 운영 대시보드 NAS 배포 + 인증 방식 결정to Streamlit 운영 대시보드 NAS 배포 — 공개 조회 + Tailscale 컨트롤 하이브리드Streamlit 운영 대시보드 NAS 배포 — 공개 조회 + Tailscale 컨트롤 하이브리드to Streamlit 운영 대시보드 NAS 배포 — 단일 URL + Tailscale 자동 감지