PostHog 手动开发环境搭建完全指南:从外部服务到hogli start的逐步实战
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
PostHog 是一个庞大的单体仓库(monorepo),前端(React/Vite/Kea)、后端(Django)、事件流(Kafka/ClickHouse)、工作流编排(Temporal)、CDP 与 Node.js 服务等组件需要协同运行。本文基于仓库内的 manual-dev-setup.md 手册,系统讲解在不依赖 Flox 自动环境的前提下,如何手动从零搭建一套可用的 PostHog 本地开发环境,涵盖外部服务启动、前端/Node.js/Django 三端依赖准备、数据库迁移、全栈启动与日常开发技巧,并给出仓库内的源码与配置佐证。
重要提示:仓库手册明确指出,本文对应的手动流程已标记为 deprecated(弃用),仓库现在推荐使用基于 Flox 的即时环境搭建(见 developing-locally)。但手动流程依然是理解 PostHog 各组件依赖关系、排查环境问题、以及在不使用 Flox 的场景下搭建环境的宝贵路线图。本文所有命令与配置均以当前仓库实际内容为准。
1. 启动外部服务:基础设施先行
PostHog 的开发环境依赖一整套外部基础设施。在手动搭建流程中,第一步就是通过 Docker Compose 把它们全部拉起来。
1.1 配置/etc/hosts:打通容器间主机名解析
PostHog 的 ClickHouse 与 Kafka 数据服务需要互相通信,为此必须把以下主机名映射到本机:
echo '127.0.0.1 kafka clickhouse clickhouse-coordinator objectstorage' | sudo tee -a /etc/hosts echo '::1 kafka clickhouse clickhouse-coordinator objectstorage' | sudo tee -a /etc/hosts两条命令分别写入 IPv4 与 IPv6 的解析记录。这些主机名在 docker-compose.dev.yml 的 Caddy 代理配置(extra_hosts: - 'web:host-gateway'等)以及 ClickHouse 的 Kafka 引擎配置(docker-compose.base.yml 中 ClickHouse 服务设置了KAFKA_HOSTS: 'kafka:9092')中都会被引用。
Podman 用户注意:如果使用的是 4.1 及以上版本的 Podman 而非 Docker,宿主机/etc/hosts会默认作为容器的基础 hosts 文件(Docker 则使用容器自身/etc/hosts),可能导致 ClickHouse 容器内主机名解析失败。解决办法是在containers.conf中设置base_hosts_file="none"。
1.2 启动 Docker Compose 开发栈
仓库根目录提供了专为本地开发设计的 Compose 文件(注意其头注释明确写明"used ONLY for local development"):
docker compose -f docker-compose.dev.yml up该文件通过extends继承 docker-compose.base.yml 中的基础服务定义,并覆盖端口映射、资源限制与开发参数。启动后docker ps应能看到类似下面的一整套服务(版本以当前仓库配置为准,与手册中的历史版本略有差异):
| 容器 | 镜像(当前仓库实际配置) | 暴露端口 | 用途 |
|---|---|---|---|
| posthog-db-1 | postgres:15.12-alpine | 5432 | 主关系数据库(用户、组织、功能开关等) |
| posthog-clickhouse-1 | clickhouse/clickhouse-server:26.6.2.158 | 8123/9000/9009/9440/8443 | 分析型列式数据库(事件、漏斗等) |
| posthog-kafka-1 | redpandadata/redpanda:v25.1.9 | 9092 | 事件流中间件(兼容 Kafka 协议) |
| posthog-zookeeper-1 | zookeeper:3.7.0 | 2181 | Kafka 协调(Redpanda 与 ClickHouse 均依赖) |
| posthog-redis-1 | redis:7.2-alpine | 6379 | 缓存与任务队列 |
| posthog-maildev-1 | maildev/maildev:2.0.5 | 1025/1080 | 本地邮件捕获与预览 |
| posthog-objectstorage-1 | seaweedfs | 19000-19001 | 对象存储(会话录制、批量导出等) |
| posthog-elasticsearch-1 | elasticsearch:7.16.2 | 9200 | Temporal 可视化的检索后端 |
| posthog-temporal-1 | temporalio/auto-setup:1.20.0 | 7233 | 工作流编排引擎 |
| posthog-temporal-ui-1 | temporalio/ui:2.10.3 | 8081 | Temporal 管理界面 |
手册中的示例
docker ps输出展示的 Kafka 镜像为bitnami/kafka:2.8.1-debian-10-r99,而当前仓库的 docker-compose.base.yml 已将 Kafka 服务替换为redpandadata/redpanda:v25.1.9(Redpanda 兼容 Kafka 协议),且 dev 栈通过kafka-init服务使用 docker/kafka/topics.txt 预创建全部 topic。这也解释了手册中"Kafka 是唯一 x86 容器、在 ARM 上可能随机段错误"的提示——Redpanda 在 Apple Silicon 上运行更稳定。
1.3 验证服务健康状态
启动后建议逐项确认服务就绪:
# 查看容器列表与状态 docker ps # 各服务的就绪日志(-n 1 只看最后一行) docker logs posthog-db-1 -n 1 # 期望:database system is ready to accept connections docker logs posthog-redis-1 -n 1 # 期望:Ready to accept connections docker logs posthog-clickhouse-1 -n 1 # 期望:Saved preprocessed configuration ... # ClickHouse 日志写入文件而非 stdout,出问题时直接查看: docker exec posthog-clickhouse-1 cat /var/log/clickhouse-server/clickhouse-server.log docker exec posthog-clickhouse-1 cat /var/log/clickhouse-server/clickhouse-server.err.logClickHouse 容器日志中可能出现get_mempolicy: Operation not permitted提示,手册说明这不会影响应用启动。如需彻底确认 ClickHouse 可用,可进入容器执行一条基本查询:
docker exec -it posthog-clickhouse-1 bash clickhouse-client --query "SELECT 1"常见启动报错排查:
| 报错 | 原因与解法 |
|---|---|
Error while fetching server API version: 500 Server Error ... | Docker Engine 未运行,先启动 Docker/OrbStack |
Exit Code 137 | 容器内存耗尽,在 OrbStack 设置中增加 RAM 配额 |
Ports are not available: exposing port TCP 0.0.0.0:5432 | 本机已有 Postgres 占用 5432 端口,用lsof -i :5432定位并停掉 |
Permission denied(Linux) | 参考 Docker 官方文档配置非 root 用户运行,或改用支持 rootless 的 Podman |
手册对 Linux 用户给出了停用本机 Postgres 服务的建议流程:
sudo service postgresql stop sudo systemctl disable postgresql.service sudo lsof -i :5432 sudo kill -9 `sudo lsof -t -i :5432`1.4 本机安装 Postgres 客户端(psycopg2 编译依赖)
即便 Postgres 服务运行在 Docker 内,本机仍需要一份 Postgres(11+)的 CLI 工具与开发库/头文件——pip/uv安装psycopg2时需要它们完成编译。
macOS:
brew install postgresql注意:这会同时安装服务端与工具,但安装后不要启动服务,以免与 Docker 容器争抢 5432 端口。
Debian 系 Linux(只装客户端与驱动,不装服务端):
sudo apt install -y postgresql-client postgresql-contrib libpq-dev不同发行版包名可能不同(例如
postgres、postgres-server、libpostgres-dev),请以各自发行版仓库为准。
2. 准备前端:nvm + pnpm + Kea 类型生成
2.1 安装 nvm 与固定 Node 版本
前端依赖 nvm 管理 Node 版本,macOS 可用brew install nvm,其他平台按官方安装脚本执行(fish shell 用户可改用 nvm.fish)。
安装后务必把 nvm 加入$PATH,否则命令行会回落到系统 Node.js 版本。然后从仓库根目录读取.nvmrc安装并激活 PostHog 生产环境使用的 Node 版本——当前仓库固定为v24.13.0:
nvm install # nvm 会读取仓库根目录的 .nvmrc nvm use2.2 启用 pnpm(Corepack)
PostHog 使用 pnpm 管理前端依赖,版本通过根目录 package.json 的packageManager字段锁定(当前为pnpm@10.29.3)。用 Corepack 一键激活:
corepack enable pnpm --version # 验证激活的版本2.3 安装依赖并生成 Kea 类型
pnpm i随后生成前端大量使用的 Kea 状态管理逻辑的类型定义:
pnpm --filter=@posthog/frontend typegen:writeKea 是 PostHog 前端的状态管理框架,其kea()逻辑会在运行时动态生成 reducer/selector 等,TypeScript 无法静态推导,因此必须借助 typegen 工具把类型写入.kea-typegen相关文件。如果只想迭代某一个 logic 文件,用:
pnpm --filter=@posthog/frontend typegen:file <path-to-logic-file><path>可以是绝对路径、仓库相对路径(如frontend/src/scenes/foo/fooLogic.ts)或前端相对路径(如src/scenes/foo/fooLogic.ts)。
首次运行 typegen 可能陷入死循环,此时按
Ctrl+C取消,git reset --hard丢弃所有改动后重新运行pnpm typegen:write,第二轮生成完成后可能还需要再丢弃一次改动。
3. 准备 Node.js 服务:brotli + Rust 工具链
PostHog 的部分 Node.js 服务(CDP 工作流、会话录制、日志摄取等,见 hogli.yaml 中 nodejs 单元的说明)在构建时需要系统库与 Rust 工具链。
macOS:
brew install brotli rustup rustup default stable rustup-init # 选择 1 使用默认安装Debian 系 Linux:
sudo apt install -y brotli curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # 选择 1 使用默认安装
然后安装 Node.js 服务的全部依赖(服务本体稍后统一启动):
pnpm --filter=@posthog/nodejs install常见报错与解法:
| 报错 | 解法 |
|---|---|
ld: symbol(s) not found for architecture arm64 | OpenSSL 构建标志来自错误位置。执行export CPPFLAGS=-I/opt/homebrew/opt/openssl/include与export LDFLAGS=-L/opt/homebrew/opt/openssl/lib后重装 |
import gyp # noqa: E402 | 缺少python-setuptools,macOS 上brew install python-setuptools |
| Node.js 服务启动异常 | 进入nodejs目录执行pnpm rebuild与pnpm i重建原生模块 |
4. 准备 Django 后端:SAML 依赖 + Python 3.13 + uv
4.1 SAML 相关的系统依赖
SAML 认证依赖xmlsec,需要系统级库支持:
macOS:
brew install libxml2 libxmlsec1 pkg-configDebian 系 Linux:
sudo apt install -y libxml2 libxmlsec1-dev libffi-dev pkg-config
4.2 安装 Python 3.13
macOS:
brew install python@3.13Debian 系 Linux(使用 deadsnakes PPA):
sudo add-apt-repository ppa:deadsnakes/ppa -y sudo apt update sudo apt install python3.13 python3.13-venv python3.13-dev -y
手册特别强调:虚拟环境外请始终使用python3而非python(后者在某些系统上仍指向 Python 2.x);若通过 deadsnakes 安装了多个 Python 3 版本,请使用python3.13精确指定。也可以用 pyenv 管理多版本。
4.3 安装 uv 并同步依赖
uv是 PostHog 后端首选的 Python 虚拟环境与依赖管理工具,安装后任何pip命令都可以前缀uv提速。一条命令完成建环境与装依赖:
uv sync该命令读取根目录的 pyproject.toml 与uv.lock。若创建环境时出现Failed to parse警告(与pyproject.toml解析有关),只要末尾出现Activate with:行即说明环境创建成功。随后激活虚拟环境:
# bash/zsh 等 source .venv/bin/activate # fish source .venv/bin/activate.fishApple Silicon Mac 用户:首次安装 Python 包时必须指定自定义 OpenSSL 头文件(用于编译grpcio与psycopg2):
brew install openssl CFLAGS="-I /opt/homebrew/opt/openssl/include $(python3.13-config --includes)" LDFLAGS="-L /opt/homebrew/opt/openssl/lib" GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1 GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1 uv sync此后只要这两个包未变更,直接uv sync即可。若出现ERROR: Could not build wheels for xmlsec,需要核对 xmlsec 的已知编译问题。
5. 准备数据库:运行迁移脚本
此时后端代码已就绪,Postgres 与 ClickHouse 容器也在运行,但两者都是空白库,需要执行迁移创建全部表结构:
cargo install sqlx-cli # 若尚未安装 DEBUG=1 ./bin/migrate注意:
./bin/migrate是仓库根目录下的 shell 脚本(bin/migrate),并非 Django 自带的manage.py migrate的别名。
5.1bin/migrate到底做了什么
从源码看,bin/migrate 是一个聚合迁移入口,按 scope 分发执行:
- clickhouse:后台并行运行
python manage.py migrate_clickhouse与python manage.py sync_replicated_schema; - postgres:运行 Django
manage.py migrate --noinput,内置最多 10 次重试(MIGRATE_MAX_RETRIES),重试间隔指数退避(默认从 3 秒起、倍增系数 2),并通过report_migration_metric上报耗时与尝试次数;若设置了POSTHOG_POSTGRES_DIRECT_HOST则走default_direct直连(绕过 PgBouncer 以支持lock_timeout); - product databases / persons / async / cyclotron / behavioral-cohorts / flags-read-store / temporal-schedules / tasks-oauth等更多 scope,各自对应不同的数据库与迁移工具(如 Rust 侧的
migrate-cyclotron-node、migrate-behavioral-cohorts、migrate-flags-read-store)。
在本地开发(DEBUG=1)下,persons 迁移会先--ensure-database确保 persons 库存在再执行;temporal-schedules 与 tasks-oauth 等生产专用步骤会被跳过。
5.2 常见迁移报错
| 报错 | 解法 |
|---|---|
fe_sendauth: no password supplied | 数据库设置了密码但DATABASE_URL未带用户密码。执行export DATABASE_URL=postgres://posthog:posthog@localhost:5432/posthog |
psycopg2相关错误(ARM 机器) | 参考 psycopg2 官方 issue 中针对 ARM 的编译/安装步骤 |
| 迁移连不上库 | 确保容器正在运行(前台窗口或独立终端),迁移与容器是两回事 |
6. 启动 PostHog:一条命令拉起全部服务
6.1hogli start
基础设施、三端依赖与迁移都就绪后,启动整个 PostHog(后端、worker、Node.js 服务、前端,同时运行):
hogli starthogli是仓库根目录 hogli.yaml 定义的统一开发者命令行工具。从配置看,start命令会拉起 django、frontend、celery、nodejs、ingestion、postgresql、redis、kafka、clickhouse、temporal 等全部服务单元。它内部调用bin/start脚本,通过 phrocs(PostHog 自研的进程运行器,基于 Bubble Tea 构建,见 tools/phrocs/README.md)把开发进程集中在一个终端窗口内管理,支持tab切换焦点、r重启进程、q退出等快捷键。
bin/start还承担了环境预检职责(bin/start):如果.env.local中存在 1Password 引用(op://前缀),会自动通过op run --env-file解析密钥;同时用flock加独占锁防止重复启动;多个 worktree 共享名为posthog的 Compose 项目。
如需按需定制服务集合,用交互式向导生成配置文件,之后hogli start会自动采用:
hogli dev:setupmacOS/Linux 用户首次运行hogli start时会自动安装 phrocs(通过 Homebrew Tapposthog/tap或仓库内源码构建)。
手册提示:若出现
Configuration property "enable.ssl.certificate.verification" not supported in this build: OpenSSL not available at build time,说明环境中 OpenSSL 版本不对,需设置对应的环境变量后重新hogli start。
6.2 验证与演示数据
启动完成后打开http://localhost:8010查看应用(8010 端口由 docker-compose.dev.yml 中 proxy 服务的 Caddy 容器映射到内部 Django 的 8000 端口,Caddy 还按路径把/e、/i/v0/*等流量反向代理给 capture、feature-flags、plugins 等独立服务)。
首次启动若报layout.html is not defined,请等待前端编译完成再刷新。
为让新实例获得可直接操作的演示数据,运行:
DEBUG=1 ./manage.py generate_demo_data该命令是仓库内的 Django 管理命令(generate_demo_data.py),支持通过--help查看参数。首次启动时也可用内置测试账号登录:用户名test@posthog.com,密码12345678。
7. 日常开发:项目结构、分支与常用命令
环境就绪后,你可以在 http://localhost:8010 上看到 PostHog 应用,并随意修改代码(Django 与 Vite 均带热重载)。仓库结构介绍可参考 project-structure;提交变更时请基于master新建分支。
基于 hogli.yaml,日常开发还可使用以下高频命令:
| 类别 | 命令 | 说明 |
|---|---|---|
| 服务控制 | hogli up -d/hogli stop | 后台模式启动 / 停止开发进程(Docker 容器保持运行) |
| 服务控制 | hogli docker:services:down | 停止全部 Docker 基础设施服务 |
| 服务控制 | hogli docker:services:remove | 停止服务并清除全部数据卷(完全重置) |
| 健康检查 | hogli doctor | 开发环境快速体检 |
| 健康检查 | hogli doctor:ports | 预检开发栈所需宿主机端口 |
| 数据库 | hogli db:pg/hogli db:ch | 连接本地 Postgres / ClickHouse |
| 数据库 | hogli db:dump/hogli db:restore | Postgres 备份与恢复 |
| 迁移 | hogli migrations:run | 并行运行全部迁移(ClickHouse、Postgres、async) |
| 迁移 | hogli migrations:check/hogli migrations:status | 校验迁移就绪 / 查看迁移差异 |
| 演示数据 | hogli dev:demo-data | 生成演示数据(等价于python manage.py generate_demo_data) |
| 测试 | hogli test | 自动检测测试类型(Python/Jest/Playwright/Rust/Go)并运行 |
| 代码质量 | hogli lint/hogli format | 运行 Python + JS/TS 的 lint / 格式化 |
| 构建 | hogli build | 运行代码生成流水线(含智能变更检测) |
| 状态 | hogli dev:reset | 完整重置:清卷、迁移、加载演示数据、同步开关 |
8. 走向推荐路径:Flox 即时环境
手册开头明确建议新开发者改用 Flox 方案(developing-locally),其核心优势是:所有开发者获得完全一致的、可复现的工具与依赖版本,无需逐项手动安装。hogli.yaml的 services 元数据也印证了这一点——flox 被描述为"管理可复现开发环境,所有开发者获得完全相同的工具与依赖版本"。
手动流程虽然繁琐,但每一步都对应着 PostHog 真实的组件依赖:/etc/hosts对应容器间服务发现、Postgres 客户端对应psycopg2编译、brotli/Rust 对应 Node.js 原生模块、bin/migrate对应多数据库的迁移编排、hogli start对应 phrocs 进程编排。理解这套手动流程,能让你在 Flox 环境出问题时依然可以定位并修复底层环境故障。
参考链接
- 本文主要依据:manual-dev-setup.md
- 开发 Compose 覆盖:docker-compose.dev.yml
- 基础 Compose 服务:docker-compose.base.yml
- 开发者命令行定义:hogli.yaml
- 聚合迁移脚本:bin/migrate
- 进程运行器:tools/phrocs/README.md
- 演示数据管理命令:generate_demo_data.py
- Kafka topic 清单:docker/kafka/topics.txt
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考