Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
15 KiB
15 KiB
설정 파일과 초기 설정 페이지 — v1.5.7 (v1.5.11 개정)
AI Webmaker v1.5.11 · 2026-10-14 · 대상: 운영자·설치 담당자
v1.5.11: 설정 페이지 기본 포트 8795(모든 인터페이스, 겹치면 다음 포트 자동), 서비스의
/setup도 접속 토큰으로 열림, 맨 위에 설치 점검표·관리자 계정·AI 엔진 인증 카드. 처음 설치 절차는 FIRST-INSTALL.md.
1. 무엇이 바뀌었나 (요구 1·2·3)
| 1.4.18 까지 | 1.5.7 부터 | |
|---|---|---|
| 서비스 공개 주소, 소스 저장소(Gitea) 주소, AI 실행 파일 경로 같은 환경 정보 | systemd 유닛의 Environment= 줄 (PUBLIC_BASE_URL, SITES_GIT_REMOTE …) — 바꾸려면 서버에서 유닛을 편집하고 daemon-reload |
설정 파일 data/config.json (권한 0600) — 웹 초기 설정 페이지·관리자 콘솔·명령줄에서 바꾼다 |
| 처음 설치할 때 모르는 값 | 설치 스크립트가 빈 값·임시 값으로 유닛을 써 두고 나중에 사람이 고침 | 설치가 끝나면 초기 설정 페이지 주소(별도 포트, 기본 8795 — 1.5.7 은 3081) 를 알려 주고 거기서 입력. 1.5.11: 설치 점검표가 끝나기 전에는 서비스 첫 화면도 /setup 으로 넘어간다 |
| 기존 운영 서버 | — | 1.5.7 로 올린 첫 기동 때 유닛의 환경 변수를 그대로 설정 파일에 옮겨 적는다. 운영 값은 바뀌지 않는다 |
| 비밀값(토큰·비밀번호) | 일부는 유닛, 일부는 보관소 | 모두 암호화 보관소(data/credentials.json, lib/vault.js). 설정 파일에는 쓰지 않는다 |
유닛에는 배포 때 정해지는 값만 남는다: PORT, HOST, SITES_ROOT, DATA_ROOT(선택), PATH, HOME, NODE_ENV. 이 값들은 설정 파일에서 바꿀 수 없다(읽기 전용으로 보임) — 포트·경로는 웹서버(nginx/Caddy) 프록시 설정과 함께 바뀌어야 하기 때문이다.
2. 설정 파일 (lib/config.js)
- 경로: 환경 변수
WEBMAKER_CONFIG><DATA_ROOT>/config.json(기본 앱 폴더의data/config.json). - 형식:
{ "version": 1, "updatedAt", "updatedBy": "setup|cli|migrate:env", "values": { "<그룹>.<항목>": 값 } } - 우선순위: 설정 파일 > 환경 변수(유닛) > 기본값. 배포 때 정해지는 값(
runtime.*)만 환경 변수가 우선. - 서비스는 기동 맨 처음
config.apply()로 파일 값을process.env에 넣는다. 그래서 코드의 다른 부분(process.env.PUBLIC_BASE_URL등)은 그대로다. 파일이 바뀌면(설정 페이지·CLI) 다음 호출부터 새 값을 읽지만, 기동 때 한 번만 읽는 모듈의 값(아래 표 "재시작")은 서비스를 재시작해야 적용된다. - 파일이 없으면 지금 환경 변수로 파일을 만든다(
migrateFromEnv). 1.5.7 로 올린 기존 서버에서 이 일이 한 번 일어난다 ([config] 설정 파일을 환경 변수에서 만들었습니다로그).
항목표
| 그룹 | 항목 (key) |
환경 변수 | 뜻 | 기본값 | 재시작 |
|---|---|---|---|---|---|
| 서비스 | service.publicBaseUrl |
PUBLIC_BASE_URL |
사용자가 접속하는 주소. 생성 사이트의 위젯·통계·웹메일 안내 파일이 이 주소를 부른다 (필수) | http://192.168.20.66 |
○ |
service.formBaseUrl |
FORM_BASE_URL |
폼 접수 서버 주소 (비우면 공개 주소) | ○ | ||
service.adminUsers |
ADMIN_USERS |
관리자로 취급할 아이디(쉼표) | ○ | ||
service.systemdUnit |
WEBMAKER_SERVICE |
설정 페이지 "서비스 재시작" 이 재시작할 유닛 (설치 스크립트가 넣음) | |||
service.setupPort / setupBind |
WEBMAKER_SETUP_PORT / _BIND |
초기 설정 페이지 포트·바인드 (lan = 첫 사설 IPv4, 0.0.0.0 = 전체, 또는 특정 IP) |
3081 / lan | (setup 서비스) | |
| 실행 환경 (읽기 전용) | runtime.port host sitesRoot dataRoot statsLog |
PORT HOST SITES_ROOT DATA_ROOT STATS_LOG |
배포 때 정해지는 값 | 3080 / 127.0.0.1 / /var/www/sites / … | — |
| AI 엔진 | ai.claudeBin codexBin |
CLAUDE_BIN CODEX_BIN |
실행 파일 (비우면 자동 탐색) | ○ | |
ai.claudeModel claudeMaxTurns openaiMaxTurns allowInsecureTls |
CLAUDE_MODEL CLAUDE_MAX_TURNS OPENAI_ENGINE_MAX_TURNS CLAUDE_ALLOW_INSECURE_TLS |
설치 기본 모델·턴 상한·TLS 완화 | claude-opus-5-5 / 80 / 60 / 켬 | ○ | |
ai.codexUnsafe |
CODEX_UNSAFE |
v1.6.31: 샌드박스를 만들 수 없을 때 기본은 작업 거부(fail-closed). true 면 샌드박스 없이 실행(위험) | false | ○ | |
ai.maxJobMinutes maxConcurrentJobs |
WM_MAX_JOB_MINUTES WM_MAX_CONCURRENT_JOBS |
v1.6.31: 한 AI 작업 최대 시간(분, 15분 무출력도 중단) · 서버 전체 동시 AI 작업 수(넘으면 429) | 45 / 4 | ||
ai.allowInsecureTls |
CLAUDE_ALLOW_INSECURE_TLS |
v1.6.31 부터 기본 false(claude 자식의 TLS 검증 유지). 사내 프록시·자체 서명 인증서 환경에서만 true | false | ○ | |
| 서비스(보안) | service.trustedProxies |
WM_TRUSTED_PROXIES |
v1.6.31: 이 IP 에서 온 연결의 X-Forwarded-For 만 클라이언트 IP 로 믿음(속도 제한·기록). 비우면 루프백만 | ||
service.internalAllow |
WM_INTERNAL_ALLOW |
v1.6.31: 사용자가 넣는 주소·제공자 URL 이 사설/내부 주소여도 허용할 host:port 목록(쉼표) — 사내 Gitea·Arimail·AI 서버. 그 밖의 내부 주소는 차단 | |||
service.siteOrigin |
WM_SITE_ORIGIN |
v1.6.31: 생성 사이트 전용 origin(예약 — 사용자 결정 뒤 연결, 비우면 같은 origin) | ○ | ||
ai.codexSandbox |
CODEX_SANDBOX |
codex 샌드박스: auto(커널이 비특권 user namespace 를 허용하면 workspace-write, 아니면 없이 — Ubuntu 24.04 기본 kernel.apparmor_restrict_unprivileged_userns=1 에서는 샌드박스 쓰기가 모두 실패) / workspace-write / none |
auto | (다음 작업부터) | |
| 소스 보관 (Gitea) | source.provider |
SOURCE_PROVIDER |
연동 모듈 (gitea / none) |
gitea | |
source.remote web prefix |
SITES_GIT_REMOTE SITES_GIT_WEB SITES_GIT_PREFIX |
푸시 주소·웹 주소·브랜치 접두어 | / / sites | (다음 커밋부터) | |
source.apiUrl user repo |
GITEA_API_URL GITEA_USER GITEA_REPO |
API 주소·계정·저장소 (선택) | / webmaker / webmaker/sites | ||
source.token |
— (보관소 gitea) |
API 토큰 (install-gitea.sh 가 만듦) | |||
| 메일 연동 (Arimail) | mail.provider |
MAIL_PROVIDER |
연동 모듈 (none / arimail) |
none | |
mail.url apiUrl domain adminLogin |
ARIMAIL_URL ARIMAIL_API_URL ARIMAIL_DOMAIN ARIMAIL_ADMIN_LOGIN |
공개 주소·내부 API 주소·메일 도메인·관리자 ID | / / / admin | ||
mail.adminPassword |
— (보관소 arimail) |
관리자 비밀번호 | |||
| SSL | ssl.acmeDir acmeWaitMin |
WM_ACME_DIR WM_ACME_WAIT_MIN |
와일드카드 인증서 작업 폴더·수동 DNS 대기(분) | /var/tmp/webmaker-acme / 40 | ○ |
| 한도 | limits.copyMaxPages copyMaxAssets |
COPY_MAX_PAGES COPY_MAX_ASSETS |
사이트 복사 상한 | 300 / 5000 | ○ |
| 외부 API (고급) | endpoints.* |
RESEND_API_BASE OPENPROVIDER_API_BASE GOOGLE_API_BASE GOOGLE_TOKEN_URL INDEXNOW_ENDPOINT |
시험용 대체 주소 | 실제 서비스 주소 |
관리자 콘솔 › 설정의 값(모델 등급·환율·마진·메일 발송 키·도메인 요율·DNS 공급자·등록 업체(v1.5.36) …)은 그대로 data/settings.json 이다. 설정 파일은 "서비스가 돌아가는 환경" 만 다룬다.
3. 초기 설정 페이지 (setup-server.js, 요구 2)
- 별도 systemd 서비스 webmaker-setup 이 설정 파일의
service.setupPort(기본 8795, v1.5.11; 겹치면 8796… 을 차례로 잡고 설정 파일에 기록)·setupBind(기본0.0.0.0— 공인 IP 만 있는 서버에서도http://<IP>:8795/로 접속; 사설망만 열려면lan= 첫 사설 IPv4, 도커 브리지 등 가상 인터페이스 제외) 로 전용 페이지를 연다. 설치 스크립트(deploy/install.sh,deploy/remote-install.sh,deploy/remote-update.sh)가 설치·기동하고, 끝나면 접속 주소를 알려 준다:http://<서버 IP>:8795/?token=<접속 토큰>(node scripts/config.js setup-url로 언제든 다시 본다) - 인증: 접속 토큰(
data/setup.token, 0600 — 처음 기동 때 생성) 또는 웹메이커 관리자 계정 로그인. 세션은 12시간 쿠키. 로그인 시도는 IP 당 15분 10회. - 같은 화면이 서비스 안에도 있다:
https://<서비스>/setup(v1.5.11: 로그인 없이 열리고 화면 안에서 접속 토큰 또는 관리자 계정으로 들어온다 — 인증 코드lib/setupauth.js를 두 서버가 공용) 과 관리자 콘솔 › 시스템 설정 탭. 화면 코드는public/setup.js하나, API 는lib/setupapi.js하나다 (/api/setup/*↔/api/admin/config/*). - 화면 (v1.5.11 맨 위): 설치 점검표(관리자 비밀번호·AI 엔진 인증·서비스 공개 주소 —
lib/setupstate.js; 필수 항목이 남아 있으면 서비스 첫 화면/·/login이/setup으로 302, 끄기service.setupRedirect=off, 우회/login?direct=1), 관리자 계정(목록·마지막 로그인, 기본 관리자admin/admin만들기, 비밀번호 재설정, 새 관리자), AI 엔진 인증(Claude 서버 로그인/OAuth 토큰/API 키 저장·확인, OpenAI API 키/codex 로그인). 이어서 상태 카드(웹메이커 서비스·설정 페이지 서비스·Gitea·Arimail·Claude(실행 파일+인증)·Codex·Resend, "연결 확인"), 그룹별 설정 카드(출처 배지: 설정 파일/환경 변수/기본값, 재시작 표시, 비밀값은 힌트만), "이 묶음 저장"·"바뀐 값 모두 저장", 서비스 재시작(실행 중 AI 작업이 끝날 때까지 기다린 뒤sudo systemctl restart), "환경 변수에서 옮겨 적기", 연동 서비스 설치·등록 명령 안내. - 재시작 권한: 설치 스크립트가
/etc/sudoers.d/webmaker-setup에systemctl restart <유닛>만 허용하는 줄을 둔다. 없으면 화면이 수동 명령을 알려 준다. - 방화벽: v1.5.11 부터 설치·갱신 스크립트가 ufw 에 설정 페이지 포트(8795)를 허용하고 1.5.7 의 3081 사설망 규칙은 지운다(FQDN 을 모르는 서버에서도
http://<IP>:8795/가 기본 접속 위치). 접속은 토큰·관리자 로그인·시도 제한(IP 당 15분 10회)으로 보호되지만 관리 화면이므로, 점검이 끝나면sudo ufw delete allow 8795/tcp로 닫거나service.setupBind=lan으로 바꿔도 된다(서비스 안/setup·관리자 콘솔 탭은 그대로). - 새 설정 항목(v1.5.11):
service.setupRedirect(auto/off),service.allowSignup(기본 켬 — 끄면 로그인 화면의 회원가입 탭이 사라지고 API 는 403 "회원가입이 닫혀 있습니다"). - API(v1.5.11,
lib/setupapi.js):GET <base>/ready점검표,POST <base>/admin/bootstrap|create|password,PUT <base>/ai/claude|openai. 명령줄:node scripts/admin.js bootstrap.
4. 명령줄 (scripts/config.js)
node scripts/config.js list # 전체 값과 출처
node scripts/config.js get service.publicBaseUrl
node scripts/config.js set service.publicBaseUrl https://webmaker.example.com # 여러 쌍 가능
node scripts/config.js set mail.adminPassword '비밀번호' # 비밀값 → 보관소
node scripts/config.js unset source.apiUrl
node scripts/config.js import-env --unit /etc/systemd/system/webmaker.service # 유닛 → 파일 (없는 항목만)
node scripts/config.js check # 필수 값 점검 (없으면 종료 코드 2)
node scripts/config.js setup-url # 초기 설정 페이지 주소(토큰 포함)
환경 변수 DATA_ROOT·WEBMAKER_CONFIG 를 서비스와 같게 준다(기본 앱 폴더의 data/).
5. 기존 서버 올리기 (요구 3)
deploy/remote-update.sh <ssh> <앱 폴더> <유닛>— 코드 갱신·재시작 뒤 (a) 유닛의 환경 변수를 설정 파일로 옮기고 (b) webmaker-setup 서비스를 설치·기동하고 (c)deploy/install-services.sh --check로 이미 설치된 Gitea·Arimail 을 등록한다. 서비스 기동 로그에[config] 설정 파일을 환경 변수에서 만들었습니다가 한 번 찍힌다.- 이후 유닛의
Environment=PUBLIC_BASE_URL=…,SITES_GIT_*줄은 참고용이다 — 설정 파일이 우선한다.install-gitea.sh를 다시 실행하면SITES_GIT_*줄을 유닛에서 지운다. - 다른 서버로 DB 를 복사할 때(
remote-install.sh) 설정 파일과 토큰은 복사하지 않는다(서버마다 다른 값).
6. 자주 나는 메시지
| 메시지 | 원인 | 해결 |
|---|---|---|
[config] 설정 파일: … 로그만 있고 값이 바뀌지 않음 |
바꾼 항목이 "재시작 후 적용" 항목 | 설정 페이지의 "서비스 재시작" 또는 sudo systemctl restart <유닛> |
설정 페이지 "서비스 재시작" → 재시작 실패: sudo: a password is required |
sudoers 규칙 없음 | deploy/install.sh/remote-update.sh 다시 실행(규칙 생성) 또는 서버에서 직접 재시작 |
접속 토큰이 맞지 않습니다 |
토큰이 바뀜(data/setup.token 삭제·재생성) | node scripts/config.js setup-url 로 새 주소, 또는 관리자 계정으로 로그인 |
<항목>은(는) 배포 때 정해지는 값이라 여기서 바꿀 수 없습니다 |
runtime.* 항목 저장 시도 |
유닛과 웹서버 설정을 함께 고친 뒤 재시작 |
<항목>은(는) http:// 또는 https:// 로 시작하는 주소여야 합니다 등 |
형식 오류 | 안내대로 수정. 저장은 전체가 검증을 통과했을 때만 된다 |
7. 백업 · 복구 (v1.6.31, 요구 29)
deploy/remote-update.sh·deploy/install.sh가 재시작 전에node scripts/backup-data.js --tag update를 실행해 DATA_ROOT 전체를DATA_ROOT/backups/<UTC시각>-update.tar.gz(0600) 로 묶는다(최근 10개 보관,--keep N,--list).sites/의 git 저장소와 통계 로그는 크기 때문에 제외하지 않고 그대로 들어간다 — 용량이 크면--keep을 줄인다.- 복구: 서비스를 멈추고(
sudo systemctl stop <유닛>)tar -xzf DATA_ROOT/backups/<파일> -C DATA_ROOT뒤 재시작. 특정 파일만 되돌릴 때는DATA_ROOT/<파일>.bak(직전 저장본) 을 먼저 본다. 손상 파일 목록은 서버 기동 로그[jsonstore]와 관리자 콘솔 › 운영 복구에 보인다. - 두 운영 서버는 DATA_ROOT 가 다르므로(bear: 앱 폴더
data/, hostinger:/data/webmaker) 백업도 각자 서버에만 남는다 — 서로 복사하지 않는다.