OpenAnalytics 직접 호스팅 방법 및 서버 요구 사항
OpenAnalytics 설치 전 필요한 4GB RAM, 25GB 디스크, 4개 DNS 레코드 등 필수 사양을 확인하세요. ClickHouse와 Postgres 기반의 복잡한 스택 구성과 설치 과정을 상세히 안내합니다.
첫 단계 이전의 요구 사항
OpenAnalytics를 직접 호스팅하려면 4 GB RAM, 25 GB의 여유 디스크 공간, Docker Compose 플러그인이 설치된 Linux VPS, 그리고 해당 서버를 가리키는 4개의 DNS 레코드가 필요합니다. 이것이 솔직한 시작 조건이며, 첫 번째 명령어를 실행하기 전에 미리 확인해야 합니다.
이 스택은 6개의 애플리케이션 서비스와 3개의 데이터 저장소로 구성됩니다. Postgres는 계정, 사이트, API 키, 공유 링크와 같은 제어 평면을 담당합니다. ClickHouse는 원시 이벤트와 대시보드에서 읽어올 롤업 데이터를 저장합니다. Valkey는 두 번 실행되는데, 하나는 지속적인 이벤트 큐로, 다른 하나는 손실되어도 무방한 캐시로 사용됩니다. 이 두 작업은 서로 다른 축출 정책이 필요하기 때문입니다. 쿼리 게이트웨이 프로세스만이 ClickHouse를 읽을 수 있으며, 쿼리를 실행하기 전에 모든 쿼리 봉투의 Ed25519 서명을 검증합니다.
단일 바이너리와 설정 파일 하나로 구성된 환경을 원하신다면 이 도구는 적합하지 않습니다. 이 분야에서 단일 바이너리 옵션을 찾으신다면 GoatCounter가 있습니다. Go 실행 파일 하나로 동작하며 기본적으로 SQLite를 사용하므로 외부 데이터베이스가 전혀 필요 없습니다. 더 무거운 스택을 선택하면 퍼널 분석, 웹 성능 지표(web vitals), 자체 Stripe 계정을 통한 수익 기여도 분석, 그리고 MCP(model context protocol) 서버 기능을 얻을 수 있습니다. 직접 호스팅하는 분석 도구 선택하기 게시물에서 이러한 선택의 차이를 비교할 수 있습니다. 이 가이드는 이미 결정을 내리셨다는 전제하에 작성되었습니다.
먼저 4개의 DNS 레코드를 서버로 지정하십시오
Caddy는 최초 실행 시 Let's Encrypt 인증서를 요청하며, 이때 도메인 이름이 아직 해석되지 않으면 챌린지가 실패합니다. 따라서 작업을 시작하기 전에 4개의 서브도메인이 서버의 공인 IP로 해석되어야 합니다.
app.example.com는 대시보드를 서비스합니다.api.example.com은 API 및 OAuth 콜백을 서비스합니다.c.example.com는 수집기 및 추적기 스크립트를 서비스합니다.rt.example.com는 실시간 스트림을 서비스합니다.
4개의 A 레코드를 사용하거나, 1개의 A 레코드와 이를 가리키는 3개의 CNAME 레코드를 사용하십시오. 계속하기 전에 dig +short app.example.com으로 확인하십시오. 방금 추가한 도메인 이름이라도 Let's Encrypt가 사용하는 리졸버에 따라 여전히 NXDOMAIN으로 캐시될 수 있습니다. 첫 번째 인증서 발급 시도가 실패하면 잠시 기다린 후 Caddy 로그를 확인하는 것이 좋습니다. 설치 과정을 다시 실행한다고 해서 DNS 전파 속도가 빨라지지는 않습니다.
Docker Compose를 사용하여 OpenAnalytics를 직접 호스팅하는 방법
태그가 지정된 릴리스를 체크아웃하십시오. 기본 브랜치는 개발이 진행되는 곳이며, 게시된 이미지는 릴리스 태그와 일치합니다. 아래 명령은 Docker와 Compose 플러그인이 이미 설치되어 있다고 가정하며, VPS에서 Docker Compose 서비스 실행하기에서 관련 내용을 다룹니다.
git clone https://github.com/OpenLabs-so/openanalytics
cd openanalytics
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./generate-secrets.sh --domain example.com --email you@example.com --with-geoip
docker compose pull && docker compose up -d체크아웃 라인의 sed '/-/d'은 프리릴리스 태그를 제외하므로, 릴리스 후보가 아닌 최신 안정 버전을 사용하게 됩니다. --with-geoip은 생성 과정 중에 DB-IP 도시 데이터베이스를 가져옵니다. 이 단계를 건너뛰면 모든 이벤트의 국가 정보가 null로 표시되어 지리 정보 뷰에 아무것도 나타나지 않습니다. 나중에 infra/selfhost/geoip/fetch-dbip.sh를 실행하고, env/collector.env에서 GEOIP_DB_PATH=/geoip/dbip-city-lite.mmdb을 설정한 다음, docker compose up -d --force-recreate collector로 수집기를 다시 생성하여 추가할 수 있습니다. 해당 데이터베이스는 매달 갱신되므로, 도시 데이터가 부정확해지지 않도록 매달 가져오기 작업을 반복하십시오.
진행하기 전에 생성된 비밀 값을 백업하십시오
생성기는 세 가지 항목을 기록합니다. .env에는 도메인 이름과 이미지 참조가 포함됩니다. env/*.env에는 서비스별 비밀 파일이 하나씩 포함됩니다. docker-compose.override.yml에는 세 개의 Ed25519 키 쌍이 YAML 블록 스칼라 형식으로 포함되는데, 이는 여러 줄로 된 PEM 형식을 환경 변수 파일에 직접 넣을 수 없기 때문입니다. 이 모든 파일은 git-ignored 상태이며, 동일한 값으로 다시 생성할 수 없습니다.
지금 해당 파일들을 서버 외부로 복사하십시오. 각 파일의 유실은 다음과 같은 결과를 초래합니다.
- 저장소 비밀번호를 분실하면 Postgres 및 ClickHouse에 접근할 수 없으며, 컨테이너 내부에서만 재설정할 수 있습니다.
OA_CREDENTIAL_KEYRING을 분실하면 저장된 모든 타사 자격 증명을 복구할 수 없으므로, Stripe 계정을 연결한 모든 사용자는 다시 연결해야 합니다.ANONYMOUS_IDENTITY_SECRET을 분실하면 방문자 식별 기준이 초기화됩니다. 어제의 방문자가 모두 신규 방문자로 집계되어 차트에 단절이 발생합니다.AUTH_SECRET을 분실하면 모든 세션이 무효화되어 모든 사용자가 다시 로그인해야 합니다.- 서명용 개인 키를 분실하면 키 쌍을 교체해야 합니다. 데이터 손실은 없습니다.
두 개의 비밀 값은 각각 두 파일에서 바이트 단위로 동일해야 합니다. ANONYMOUS_IDENTITY_SECRET는 collector.env과 worker.env에 나타나는데, 이는 수집기(collector)가 방문자 해시를 계산하고 작업자(worker)가 이를 기록하기 때문입니다. OA_CREDENTIAL_KEYRING는 api.env과 worker.env에 나타납니다. 그 외의 모든 비밀 값은 의도적으로 단일 서비스에만 한정되어 있으며, 해당 서비스가 보유해서는 안 되는 비밀 값을 전달받으면 서비스는 시작되지 않고 종료됩니다.
스택을 실행하고 상태 확인하기
grep OA_IMAGE .env
docker compose pull
docker compose up -d
docker compose logs -f migrate
docker compose psmigrate는 Postgres와 ClickHouse 스키마를 적용한 뒤 종료되므로, migrate 컨테이너가 중지된 상태인 것이 정상입니다. tracker-build은 oa.js을 컴파일하여 Caddy가 제공하는 볼륨에 저장한 뒤 종료됩니다. 그 외의 모든 서비스는 docker compose ps에서 healthy 상태여야 합니다. 서비스가 반복적으로 재시작된다면 대부분 환경 설정 검증에 실패한 경우이며, 로그에는 재시작마다 하나씩이 아니라 모든 문제가 한 번에 나열됩니다. 흔한 원인 두 가지는 변수를 비워두어 설정되지 않은 것으로 간주되지 않고 거부되는 경우와, 비밀 값을 잘못된 서비스 파일에 배치한 경우입니다.
arm64 환경이나 특정 브랜치에서 빌드할 때는 게시된 이미지가 없으므로 docker compose up -d --build을 사용하여 로컬에서 빌드해야 합니다. 4 GB 메모리를 가진 호스트는 빌드 도중 메모리가 부족해질 수 있습니다. 빌드 중에만 필요한 스왑을 먼저 추가하십시오:
fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab빌드에는 약 10분이 소요됩니다. 이미지를 내려받는 데는 몇 분 정도 걸리며, 이것이 릴리스 이미지가 존재하는 이유입니다.
첫 번째 계정 즉시 선점하기
https://app.example.com를 엽니다. 아직 아무도 로그인하지 않은 배포 환경에는 로그인 폼이 나타나지 않으며, 대신 첫 번째 계정을 생성하라는 메시지가 표시됩니다. 해당 계정은 영구적으로 관리자 권한을 가지며, 배포 설정 화면을 볼 수 있는 유일한 계정입니다. 계정이 생성되면 해당 경로는 409을 반환하므로, 다른 사람이 뒤따라 들어올 수 없습니다. 스택이 정상 상태가 된 즉시 이 작업을 수행하십시오. 다음 주로 미루어서는 안 됩니다.
트래커 설치
대시보드에 사이트를 추가하면 태그가 제공됩니다. 태그의 형식은 다음과 같습니다.
<script
async
src="https://c.example.com/oa.js"
data-key="YOUR_TRACKING_KEY"
data-collector="https://c.example.com"
></script>이 태그를 페이지의 head 섹션에 삽입하십시오. 추적 키는 설계상 공개되어 있으므로, 누구나 읽을 수 있는 HTML 영역에 위치해도 무방합니다. 스크립트는 window.oa를 설치하며, oa("track", ...)와 같은 호출은 스텁(stub)에 의해 대기열에 저장되었다가 파일이 로드되면 전송됩니다. 따라서 페이지 로드 초기에 발생한 사용자 정의 이벤트도 유실되지 않습니다. 만약 페이지 내 다른 요소가 이미 window.oa을 사용 중이라면, 트래커는 대신 window.openanalytics로 설치됩니다.
그다음 전체 경로를 처음부터 끝까지 확인하십시오.
curl -s https://c.example.com/oa.js -o /dev/null -w '%{http_code} %{size_download}\n'
curl -s https://api.example.com/health | head -c 200
docker compose logs --tail=50 worker | grep -i batch첫 번째 명령은 200과 수 킬로바이트의 데이터를 출력해야 합니다. 사이트의 페이지를 로드한 뒤, 몇 초 내에 워커 로그에서 배치(batch) 라인을 확인하십시오. 수집기는 이벤트를 수락하는 즉시 202를 응답하며, 202은 이벤트가 저장된 것이 아니라 대기열에 추가되었음을 의미합니다. 워커는 이벤트를 ClickHouse로 이동시키는 역할을 합니다. 이벤트는 수락되었으나 대시보드에 아무것도 나타나지 않는다면 워커가 차단된 상태이며, Valkey 대기열 깊이가 계속 증가하는 것으로 이를 확인할 수 있습니다. 일반적인 원인은 worker.env의 ClickHouse 자격 증명이 잘못되었거나, 마이그레이션으로 추가된 테이블에 권한이 부여되지 않은 경우입니다.
수집기는 공개하고 대시보드는 인증 뒤에 배치하기
Caddy는 compose 파일 내부에 포함되어 있으며 4개의 도메인 이름에 대한 인증서를 스스로 발급받으므로, 기본 경로에 대해 별도의 프록시 작업을 수행할 필요가 없습니다. 만약 서버에서 이미 Nginx 리버스 프록시를 운영 중이라면, 제공된 infra/selfhost/nginx.conf.example를 사용하여 스택 앞단에 배치하고 헤더 처리 설정은 그대로 유지하십시오.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header CF-Connecting-IP "";
proxy_set_header True-Client-IP "";
proxy_set_header Fly-Client-IP "";수집기는 클라이언트 IP에서 일일 방문자 해시를 추출하므로, 반드시 연결 정보에서 직접 주소를 가져와야 하며 헤더를 참조해서는 안 됩니다. 신뢰할 수 없는 홉에서 CF-Connecting-IP을 그대로 전달하면 호출자가 임의의 주소를 사칭할 수 있으며, 이는 위치 정보의 정확성을 떨어뜨리고 방문자 수를 부풀리는 결과를 초래합니다.
접근 제어는 호스트 이름별로 명확히 구분됩니다. c.와 rt.는 측정 대상 사이트의 모든 방문자가 접근할 수 있어야 하므로, 이 두 경로 앞에는 기본 인증(basic auth)이나 IP 허용 목록을 설정하지 마십시오. app.과 api.은 로그인한 사용자만 접근할 수 있으면 됩니다. 대시보드는 애플리케이션 자체 인증 기능을 통해 보호됩니다. env/api.env의 AUTH_PASSWORD_SIGNIN=enabled 설정을 통해 비밀번호 로그인이 기본적으로 활성화되며, Google 또는 GitHub 버튼은 해당 제공업체의 클라이언트 ID와 클라이언트 시크릿이 모두 존재할 때만 나타납니다. 매직 링크는 메일 전송 수단이 필요하며, 설정되지 않은 경우 API는 전송 내용을 아웃박스에 기록만 할 뿐 실제 발송은 이루어지지 않으며 오류도 발생하지 않습니다.
대시보드 작동 여부는 하나의 설정이 결정합니다. env/api.env의 AUTH_TRUSTED_ORIGINS은 대시보드 오리진과 정확히 일치해야 합니다. 이 값이 잘못되었거나 누락되면 API는 CORS(cross-origin resource sharing) 헤더를 응답하지 않으며, 브라우저는 모든 호출을 거부합니다. 결과적으로 docker compose ps는 모든 상태가 정상이라고 보고하지만, 대시보드는 레이아웃만 표시될 뿐 데이터는 나타나지 않게 됩니다.
프록시 설정을 변경하는 김에 자동화된 트래픽도 처리하십시오. 크롤러는 일반 사용자처럼 수집기에 접근하며, 이들의 페이지 뷰는 ClickHouse에 기록되어 통계에 포함됩니다. 서버 수준에서 AI 크롤러를 차단하면 데이터베이스의 정확도를 유지하고 불필요한 디스크 사용을 방지할 수 있습니다.
여기서 쿠키리스(cookieless)가 의미하는 바와 그 대가
쿠키는 사용되지 않습니다. 방문자 식별자는 솔트(salt)가 적용된 해시값이며, 이 솔트는 매일 변경됩니다. 원본 IP 주소는 절대 저장되지 않습니다. 지리적 위치 정보는 로컬 디스크에 있는 DB-IP 파일을 참조하여 확인하므로, 방문자 정보가 호스트 외부로 전송되지 않습니다.
이 방식의 장점은 방문자의 기기에 영구적인 식별자를 남기지 않는다는 점입니다. 바로 이 점 때문에 EU ePrivacy 동의 규칙에 따른 추적기 규제 대상에서 제외됩니다. 이러한 이유로 이와 같은 집계 전용 설정은 일반적으로 동의 배너 없이 운영됩니다. 물론 저장하는 데이터의 종류와 보관 기간에 대해서는 여전히 GDPR이 적용되며, 구체적인 법적 판단은 README가 아닌 귀하의 법률 자문이 결정해야 합니다.
이 방식의 대가는 일자별 식별이 불가능하다는 점입니다. 솔트가 매일 변경되므로 월요일에 방문한 사용자가 수요일에 다시 방문하면 설계상 두 명의 방문자로 집계되며, 이를 우회할 방법은 없습니다. 일일 순 방문자 수는 정확하게 산출됩니다. 주간 및 월간 순 방문자 수는 일일 집계를 합산하여 산출하므로 실제 도달 범위보다 과대평가될 수 있습니다. 따라서 장기적인 기간을 대상으로 한 "재방문자" 수치는 해당 명칭이 의미하는 바를 정확히 측정하지 못합니다. 세션과 방문 경로는 단일 일자 내에서는 신뢰할 수 있습니다. ANONYMOUS_IDENTITY_SECRET를 변경하는 것은 일자 변경과 동일한 효과를 내므로, 이를 일상적인 관리 작업이 아닌 데이터 변경으로 간주해야 합니다.
수집기는 Do Not Track 및 Global Privacy Control을 준수합니다. 이는 사이트에 개인 데이터를 판매하거나 공유하지 말라는 브라우저 신호입니다. 스크립트 태그는 동일한 목적을 위해 data-respect-gpc, data-respect-dnt, 그리고 동의가 부여될 때까지 모든 수집을 보류하고 oa.consent 키를 사용하여 localStorage에 답변을 기억하는 data-require-consent와 같은 자체 스위치를 제공합니다. data-storage="none"를 설정하면 브라우저 저장이 완전히 비활성화됩니다.
6개월 뒤 디스크가 가득 차는 이유
이는 셀프 호스팅 분석 서버를 운영할 때 가장 흔히 발생하는 문제이며, 보통 이벤트 데이터 자체가 원인은 아닙니다.
먼저 이미지 파일을 확인해야 합니다. 릴리스마다 10개의 이미지가 배포되며, 디스크에서 약 13 GB를 차지합니다. 업그레이드 시에는 기존 버전을 삭제하기 전에 새로운 세대를 먼저 내려받으므로, 잠시 동안 두 세대의 이미지를 모두 보유하게 됩니다. 페이지 뷰가 단 하나도 발생하기 전에 이미 25 GB의 용량이 필요한 이유가 바로 이것입니다.
다음은 스냅샷입니다. snapshot.sh은 스택을 중지하고 모든 비밀 값을 포함한 두 데이터 볼륨을 아카이브한 뒤 다시 시작합니다. ClickHouse는 백그라운드에서 파트 병합을 수행하므로 병합 중에 복사본을 생성하면 데이터 일관성이 깨질 수 있습니다. 따라서 안전한 복사를 위해서는 반드시 콜드 카피(cold copy) 방식을 사용해야 합니다. upgrade.sh은 업그레이드 직전에 자동으로 스냅샷을 생성하므로, 제한을 설정하지 않으면 아카이브가 디스크에 계속 쌓이게 됩니다.
./snapshot.sh create --label before-something-risky
./snapshot.sh list
./snapshot.sh --keep 3디스크 용량이 한계에 가까워졌다면 업그레이드 전에 이전 세대의 이미지를 정리하십시오. 실행 중인 컨테이너가 참조하는 이미지는 삭제되지 않으므로 스택이 가동 중일 때 수행해도 안전합니다.
docker image prune -a -f그다음은 이벤트 데이터 자체입니다. ClickHouse는 컬럼 기반 데이터를 강력하게 압축하므로 원시 이벤트 데이터의 증가 속도는 예상보다 느립니다. 대시보드가 읽어 들이는 롤업 테이블은 원시 테이블에 비해 크기가 매우 작습니다. 추측하지 말고 직접 측정하십시오.
docker system df -v
docker compose exec clickhouse df -h /var/lib/clickhouse테이블별 수치를 확인하려면 infra/selfhost/env/ 아래에 생성된 ClickHouse 자격 증명을 사용하여 다음 명령을 실행하십시오.
SELECT table, formatReadableSize(sum(bytes_on_disk)) AS size, sum(rows) AS row_count
FROM system.parts
WHERE active
GROUP BY table
ORDER BY sum(bytes_on_disk) DESC;첫째 주와 넷째 주에 각각 수치를 측정하십시오. 두 시점의 데이터를 비교하면 증가율을 알 수 있으며, 이를 통해 볼륨 크기를 조정해야 할 시점을 파악할 수 있습니다. 2026년 8월 기준으로 셀프 호스팅 가이드에는 원시 이벤트에 대한 보존 기간이나 TTL(time-to-live) 설정 기능이 명시되어 있지 않습니다. 따라서 오래된 행이 자동으로 삭제될 것이라고 가정하지 말고, 측정된 증가율에 맞춰 디스크 크기를 산정하십시오.
삭제와 관련하여 주의해야 할 함정이 하나 있습니다. 사이트나 계정을 삭제하면 워커(worker)를 위한 작업이 큐에 쌓이는데, 이 워커가 정상 작동하려면 CLICKHOUSE_MAINTENANCE_USER 및 CLICKHOUSE_MAINTENANCE_PASSWORD가 설정되어 있어야 하며 ClickHouse에 대응하는 oa_maintenance 사용자가 존재해야 합니다. 이 설정이 없으면 삭제 작업이 큐에 무한히 대기하게 됩니다. 사이트는 대시보드에서 사라지지만 모든 행은 디스크에 그대로 남게 되어, 정리가 완료된 것처럼 보이지만 실제로는 공간이 확보되지 않는 상황이 발생합니다.
업그레이드와 세 가지 비용
git fetch --tags
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./upgrade.shupgrade.sh은 작업을 수행하기 전에 세 가지 비용을 출력합니다. 다운타임은 실제로 발생합니다. 수집기가 중단된 동안 시도된 이벤트는 추적기가 재시도하지 않으므로 유실됩니다. 롤백은 데이터를 손실합니다. rollback.sh --to backups/<snapshot>은 두 저장소를 모두 교체하며 해당 스냅샷 이후 기록된 모든 행을 폐기하기 때문입니다. 디스크는 세 번째 비용이며, 앞서 설명한 스냅샷 더미가 이에 해당합니다.
두 가지 재시작 규칙은 실수하기 쉽습니다. API보다 먼저 쿼리 게이트웨이를 실행하십시오. 최신 API는 이전 게이트웨이가 거부하는 쿼리 필드를 전송할 수 있기 때문입니다. 또한 ClickHouse는 재시작이 아닌 재생성이 필요합니다. docker compose restart은 컨테이너의 기존 환경을 재사용하며 사용자가 수정한 내용을 무시하고 실행하기 때문입니다.
docker compose up -d --force-recreate clickhouse대시보드에도 동일한 형태의 함정이 있습니다. env/web.env에 있는 세 가지 NEXT_PUBLIC_* 오리진은 브라우저 번들로 컴파일되며 컨테이너가 시작될 때 치환됩니다. 따라서 잘못된 호스트 이름을 호출하는 대시보드는 docker compose up -d --force-recreate web로 수정해야 하며 restart로는 해결되지 않습니다. 웹 컨테이너 로그에는 시작 시 적용된 오리진이 출력되므로, 이를 확인하는 것이 수정 사항이 반영되었는지 확인하는 가장 빠른 방법입니다.
설정 변경 후 ClickHouse가 시작되지 않는다면 로그의 첫 번째 줄을 읽으십시오. oa-entrypoint:으로 시작하는 줄은 진입점이 사용자가 설정한 값을 거부하고 있음을 의미합니다. 그 외의 메시지는 일반적으로 설정 파일이 유효하지 않은 XML임을 뜻하며, 가장 흔한 원인은 XML 주석 내부에 이중 하이픈을 사용하는 경우입니다. 이는 해당 위치에서 허용되지 않습니다.
AGPL-3.0 라이선스 및 명칭
이 코드는 AGPL-3.0 라이선스를 따릅니다. 수정하지 않은 상태로 본인의 사이트에서 운영하는 경우에는 어떠한 공개 의무도 발생하지 않습니다. 코드를 수정하고 해당 수정 버전을 네트워크 서비스로 운영할 때부터 의무가 발생합니다. 이 경우 라이선스는 서비스 사용자에게 수정된 소스 코드를 제공하도록 요구합니다. 이는 귀하의 인스턴스에서 클라이언트에게 대시보드를 제공하는 경우나, 이를 제품에 포함하여 판매하는 경우 모두에 해당합니다. 변경 사항을 공개 포크(public fork)로 유지하는 것만으로도 별도의 추가 절차 없이 의무를 충족할 수 있습니다.
브랜드는 코드와 별개입니다. "OpenAnalytics"라는 명칭과 프로젝트의 호스팅 도메인은 원작자가 운영하는 인스턴스를 식별하기 위한 것이며, 라이선스 허여 범위에 포함되지 않습니다. 귀하의 배포 환경에서는 브랜드를 포함하지 않고 소프트웨어를 실행하게 되므로, 유료 고객에게 서비스를 제공하기 전에 해당 서비스에 고유한 이름을 부여하십시오.
FAQ
1 GB VPS에서 OpenAnalytics를 실행할 수 있습니까?
아니요. 이 프로젝트는 약 4 GB의 RAM과 25 GB의 여유 디스크 공간을 요구합니다. 한 번의 배포로 6개의 애플리케이션 서비스와 Postgres, ClickHouse, 그리고 2개의 Valkey 인스턴스가 함께 실행되기 때문입니다. ClickHouse 하나만으로도 적지 않은 리소스를 점유합니다. 1 GB 환경에서는 컨테이너가 시작되더라도 커널의 OOM(Out-of-Memory) 킬러가 보통 ClickHouse와 같은 프로세스를 종료시킵니다. 1 GB 플랜을 반드시 사용해야 한다면, 외부 데이터베이스 없이 SQLite에서 동작하는 GoatCounter와 같은 단일 바이너리 도구를 사용하십시오.
OpenAnalytics를 사용하면 쿠키 배너가 필요합니까?
이는 법률 전문가와 상의해야 할 문제이나, 기술적인 측면에서는 귀하에게 유리합니다. 쿠키를 사용하지 않으며, 방문자 식별자는 매일 변경되는 솔티드 해시(salted hash)를 사용합니다. 원본 IP 주소는 저장되지 않으므로 방문자를 식별할 수 있는 영구적인 데이터는 기록되지 않습니다. 다만, 무엇을 저장하고 얼마나 오래 보관할지는 여전히 GDPR의 적용을 받습니다. 수집을 명시적으로 제어하려면 스크립트 태그에 data-require-consent를 설정하십시오. 이 경우 동의를 얻기 전까지는 추적기가 아무것도 수집하지 않으며, 동의 여부는 oa.consent 하위의 localStorage에 저장됩니다.
이벤트는 202를 반환하는데 왜 대시보드에 나타나지 않습니까?
202은 수집기가 이벤트를 수락하고 대기열에 넣었다는 의미이지, 저장을 완료했다는 의미는 아닙니다. 워커(worker)가 해당 대기열에서 데이터를 가져와 ClickHouse로 전달하므로, 요청은 성공하는데 대시보드가 비어 있다면 워커에 문제가 있는 것입니다. docker compose logs --tail=50 worker을 읽고 Valkey 대기열의 깊이를 확인하십시오. 대기열이 계속 늘어난다면 워커가 차단된 상태입니다. 주된 원인은 worker.env의 ClickHouse 자격 증명이 잘못되었거나, 최근 마이그레이션으로 생성된 테이블에 대한 권한이 누락된 경우입니다.
모든 컨테이너가 정상인데 왜 대시보드가 비어 있습니까?
먼저 env/api.env의 AUTH_TRUSTED_ORIGINS을 확인하십시오. 이 값은 대시보드 오리진과 정확히 일치해야 합니다. 일치하지 않으면 API가 CORS 헤더를 내보내지 않으며, 브라우저가 모든 호출을 거부하여 레이아웃은 보이지만 데이터는 표시되지 않게 됩니다. 두 번째로 확인할 사항은 env/web.env 내의 세 가지 NEXT_PUBLIC_* 값입니다. 이 값들은 웹 컨테이너가 시작될 때 치환됩니다. 값을 수정하려면 docker compose up -d --force-recreate web가 필요합니다. 단순히 재시작만 하면 이전 값이 유지되기 때문입니다.
AGPL-3.0 라이선스 때문에 고객에게 서비스를 제공할 수 없습니까?
아니요, 단 하나의 조건만 따릅니다. 코드를 수정하지 않고 그대로 실행한다면 누구에게도 의무가 발생하지 않습니다. 코드를 수정하여 다른 사람들이 사용하는 서비스로 운영할 경우, 해당 사용자들에게 수정된 소스 코드를 제공해야 합니다. 공개 포크(public fork)를 제공하는 것으로 이 조건을 충족할 수 있습니다. 별개로, "OpenAnalytics"라는 이름은 코드와 함께 라이선스되지 않으므로, 귀하가 판매하는 서비스에는 고유한 이름을 사용해야 합니다.