--- title: Outline Wiki updated: 2026-04-29 tags: [k3s, wiki, outline] --- ## 개요 Outline은 팀 위키/문서 관리 플랫폼. K3s 클러스터에 배포. | 항목 | 값 | |------|-----| | URL | https://outline.inouter.com | | 네임스페이스 | outline | | 이미지 | `outlinewiki/outline:1.7.0` (2026-04-29 0.82.0 → 1.7.0 메이저 업그레이드, OIDC SameSite 쿠키 수정 — [[../../history/2026-04-29-outline-1-7-0-upgrade|history]]) | | 인증 | Gitea OAuth2 (OIDC) | | 기본 언어 | 한국어 | ## 구성 요소 | 컴포넌트 | 설정 | |-----------|------| | DB | Patroni HA via OpenWrt HAProxy (`192.168.9.1:5432`), DB명: outline, 유저: outline | | Redis | outline-redis (outline 네임스페이스 내 전용) | | 파일 저장소 | 로컬 (Longhorn PVC 5Gi, `/var/lib/outline/data`) | | TLS (Traefik) | wildcard-inouter-tls (*.inouter.com) | | TLS (CDN) | *.inouter.com wildcard (cert-manager, GTS WR1 발급) 수동 업로드 | | CDN | BunnyCDN **iron-kr-nowaf** 존 (ID 5720695, WAF 없음, 쿠키 허용) — 2026-04-21 iron-kr에서 분리 이전 | | Bunny Origin | https://220.120.65.245:9443 → APISIX (Traefik 미경유) | | DNS | outline.inouter.com CNAME → iron-kr-nowaf.b-cdn.net (Cloudflare, proxied OFF) | | Ingress | **APISIX ApisixRoute `outline` (ssl_id 4e7704e0, route_id ce4d2d80)** — 2026-04-21 변경. Traefik IngressRoute는 롤백 대비 유지 중이지만 비활성 경로 | ## 인증 (Gitea OAuth2) | 항목 | 값 | |------|-----| | OIDC Provider | Gitea (gitea.inouter.com) | | Client ID | cb804835-416c-4730-86b4-26d2c129b164 | | Redirect URI | https://outline.inouter.com/auth/oidc.callback | | OIDC Endpoints | authorize, access_token, userinfo (Gitea 표준) | | Client Secret | Vault `secret/apps/outline` 참조 | ## 시크릿 Kubernetes Secret: `outline-secrets` (outline 네임스페이스) - SECRET_KEY, UTILS_SECRET, DATABASE_URL, REDIS_URL - OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC 엔드포인트들 ## pgcat 연동 현재 pgcat 미사용 (직접 PostgreSQL 접속). 필요 시 pgcat pool 추가 가능. ## MCP 연동 Outline MCP 서버 도입 시 헤임달이 직접 문서 CRUD 가능. - 참고: https://github.com/Vortiago/mcp-outline - heimdall `~/.claude.json` `/root` 프로젝트 mcpServers에 `outline` 항목 추가 (stdio, `uvx mcp-outline`, `OUTLINE_API_KEY`는 Vault `secret/apps/outline` brokkr-api-key, `OUTLINE_API_URL=https://outline.inouter.com`) - 새 컬렉션 `agent-qna` (id `c3ab34ab-fae4-4642-8f4e-12728e293e1b`) — 에이전트 간 장문 Q&A 교환 공간 (kappa↔heimdall이 tmux로 짧게 질문 → 답변은 여기에 작성) DB endpoint는 OpenWrt HAProxy(`192.168.9.1:5432`) 경유. 과거 Patroni failover 사고 이력: [[2026-04-08-patroni-failover-incident|history]] ## Discord 통지 파이프라인 `agent-qna` 컬렉션에 새 문서가 만들어지면 heimdall Discord 채널(#heimdall, id `1488119168145555486`)에 자동 알림이 뜬다. 다른 컬렉션은 무시한다. ``` Outline (documents.create webhook) → n8n webhook (https://n8n.inouter.com/webhook/outline-to-discord) → Code 노드 (collectionId 필터 + Discord embed 빌드) → HTTP Request 노드 (Discord Bot API: POST /channels/{id}/messages) ``` ### 구성 요소 위치 | 항목 | 값 | |------|-----| | n8n workflow id | `8P714i5oBs9HkZPK` | | n8n workflow 이름 | `outline-to-discord (heimdall)` | | n8n webhook path | `/webhook/outline-to-discord` (POST, responseMode=onReceived) | | n8n 노드 구성 | Webhook → Filter+Format(Code) → Discord POST(HTTP) | | Outline webhook id | `ede9327f-b09e-4f7e-ab56-c507d3d1b3a6` (`documents.create` 이벤트) | | Outline collection 필터 | `c3ab34ab-fae4-4642-8f4e-12728e293e1b` (agent-qna) — Code 노드 안에 하드코딩 | | Discord channel | guild `1469999069190557799` 의 `#heimdall` 채널 (id `1488119168145555486`) | | Discord bot | username `Heimdall` (id `1487694864232611922`) | ### 시크릿 | 비밀 | Vault 경로 | |------|-----------| | Discord bot token | `secret/apps/discord` → `bot_token` (현재는 n8n Code 노드에 하드코딩되어 있음 — Credentials로 분리하는 게 더 깔끔, 후속 작업) | | Discord channel/guild ID | `secret/apps/discord` → `heimdall_channel_id`, `heimdall_guild_id` | | n8n API key | `secret/apps/n8n` → `api_key` (label: `heimdall-automation`) | | n8n owner login | `secret/apps/n8n` → `email`(`kappa@inouter.com`), `password` | | Outline API token | `secret/apps/outline` → `brokkr-api-key` | ### 메시지 포맷 (Discord embed) - title: `📝 ` - url: `https://outline.inouter.com` - description: 본문 앞 200자 (개행 → 공백) - author.name: `outline / agent-qna · ` - color: `0x00bcd4` (cyan) - timestamp: `payload.model.createdAt` ### 트러블슈팅 증상별 점검 순서: 1. **알림이 아예 안 옴** - Outline UI 또는 API로 webhook subscription 활성 확인 ```bash curl -sS -X POST https://outline.inouter.com/api/webhookSubscriptions.list \ -H "Authorization: Bearer $OL_TOKEN" -d '{}' | jq . ``` - n8n에서 workflow active 여부 확인 (`/api/v1/workflows/8P714i5oBs9HkZPK`) - n8n executions에 webhook 도달했는지 확인 (`/api/v1/executions?workflowId=8P714i5oBs9HkZPK&limit=10`) 2. **n8n에 도달하나 Discord POST가 안 일어남** - 거의 항상 collectionId 필터 미스매치. Filter+Format Code 노드의 `out items: 0` 이면 정상 (필터된 것) - 필터를 통과해야 하는데 0 items면 payload.event 또는 payload.model.collectionId 구조 확인 3. **n8n DB connection timeout** - n8n pod 재시작: `kubectl -n n8n delete pod -l app.kubernetes.io/name=n8n` - pgcat → 192.168.9.1:5432 (Patroni leader) 경로 확인 4. **Discord 401/403** - bot token 재발급 필요 (`secret/apps/discord` 갱신, n8n Code 노드의 하드코딩도 함께 갱신) - bot이 채널에 access 권한 있는지: `GET /channels/{channel_id}` 200이면 OK 5. **Outline → n8n 호출이 BunnyCDN 508** - 일시적. 재시도하면 풀린다. BunnyCDN edge의 `cdn-loopcount` 룰 (자세한 원인 불명, retry로 회피) ### 후속 작업 (선택) - [ ] Discord bot token을 n8n Credentials로 분리 (현재 Code 노드에 하드코딩) - [ ] Outline signing secret 지원되면 HMAC 서명 검증 추가 (현재 미적용 — 같은 인프라 내부 호출이라 위험 낮음) - [ ] `documents.update` 이벤트도 추가 (현재 create만) - [ ] 다른 컬렉션 (예: incident postmortem)도 동일 패턴으로 통지 추가