Mindwendel v0.4.9 Ubuntu 22.04 安装指南
在干净的 Ubuntu 22.04 上从源码编译安装 Mindwendel v0.4.9-kits-1:asdf 安装 Elixir 1.18 + Erlang 27 + Node 22、PostgreSQL 初始化、Mix Release 构建、数据库迁移、Systemd 服务配置、Nginx 反代与 SSL 终止、升级维护流程。
Mindwendel v0.4.9 Ubuntu 22.04 安装指南
目标:在一台干净的 Ubuntu 22.04 服务器上,从源码编译方式安装 Mindwendel v0.4.9-kits-1 并完成 PostgreSQL 数据库、运行用户、Systemd 服务的完整配置。覆盖基础环境准备、依赖安装、源码获取、Elixir/Phoenix Release 构建、数据库初始化、服务启动与验证。
一、前置条件
硬件要求
| 项目 | 最低 | 推荐 |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| 内存 | 1 GB | 2 GB(编译阶段需 2 GB 以上) |
| 磁盘 | 5 GB | 10 GB |
| 网络端口 | 4000(Web)、5432(PostgreSQL 本地) | — |
系统信息
lsb_release -a
预期输出:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.5 LTS
Release: 22.04
Codename: jammy
需要安装的运行时
Mindwendel 基于 Elixir + Phoenix 技术栈,生产部署有两种路径:
- Docker Compose 方式(推荐,见 B2 篇)
- 源码编译 + Systemd 方式(本篇)
源码方式需要安装:
- Elixir 1.18.4 + Erlang/OTP 27.3.4.16(编译和运行都需要)
- Node.js 22.x(编译前端 assets 时需要)
- PostgreSQL 14+(必需,运行时唯一外部依赖)
- Mix / Hex(Elixir 的包管理器,首次运行时自动安装)
⚠️ 注意:编译阶段内存要求较高(建议 ≥ 2 GB),生产运行时约 300-500 MB 内存。如果服务器只有 1 GB 内存,建议使用 Docker Compose 方式或先增加 swap。
二、基础环境准备
2.1 系统更新与基础工具
sudo apt-get update
sudo apt-get install -y git build-essential curl wget ca-certificates gnupg libssl-dev \
postgresql postgresql-contrib pkg-config cmake locales
预期输出(节选):
Reading package lists... Done
Building dependency tree... Done
The following NEW packages will be installed:
build-essential ca-certificates cmake curl git gnupg libssl-dev locales pkg-config
postgresql postgresql-contrib wget
...
Unpacking git (1:2.34.1-1ubuntu1.15) ...
Setting up postgresql (14+238.pgdg22.04+1) ...
...
Processing triggers for man-db (2.10.2-1) ...
2.2 创建运行用户
sudo useradd --system --home /opt/mindwendel --shell /bin/false mindwendel
sudo mkdir -p /opt/mindwendel
sudo chown mindwendel:mindwendel /opt/mindwendel
2.3 配置 PostgreSQL
sudo -u postgres psql <<'EOSQL'
CREATE USER mindwendel WITH PASSWORD 'q1w2e3r4';
CREATE DATABASE mindwendel_prod OWNER mindwendel;
GRANT ALL PRIVILEGES ON DATABASE mindwendel_prod TO mindwendel;
\q
EOSQL
预期输出:
CREATE ROLE
CREATE DATABASE
GRANT
验证数据库连接:
sudo -u postgres psql -c "SELECT 1;" -U mindwendel -d mindwendel_prod
预期输出:
?column?
----------
1
(1 row)
三、安装 Elixir + Erlang
推荐使用 asdf(版本管理器)安装 Elixir 和 Erlang,便于版本切换和多实例共存。
3.1 安装 asdf
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.1
echo '. ~/.asdf/asdf.sh' >> ~/.bashrc
echo '. ~/.asdf/completions/asdf.bash' >> ~/.bashrc
source ~/.bashrc
asdf --version
预期输出:
0.14.1-<hash>
3.2 安装 Erlang/OTP 27
asdf plugin add erlang
asdf install erlang 27.3.4.16
asdf global erlang 27.3.4.16
erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell
预期输出:
"27"
💡 技术拓展:Elixir 运行在 BEAM(Bogdan's Erlang Abstract Machine)上,BEAM 的前身为 Joe Armstrong 设计的 Erlang VM。BEAM 以"软实时"和"高并发"闻名——单 BEAM 实例可轻松支撑 100 万+ 轻量级进程(内存仅数 KB),这也是 Phoenix LiveView 能支撑高并发实时协作的底层保障。Mindwendel 的 LiveView 进程模型:每个活跃的头脑风暴页面对应一个 LiveView 进程树,进程间通过 pub/sub(Phoenix.PubSub)做实时事件广播。
3.3 安装 Elixir 1.18.4
asdf plugin add elixir
asdf install elixir 1.18.4-otp-27
asdf global elixir 1.18.4-otp-27
elixir --version
预期输出:
Elixir 1.18.4 (compiled with Erlang/OTP 27)
3.4 安装 Mix / Hex
mix local.hex --force
mix local.rebar --force
hex --version
预期输出:
* creating /root/.hex
https://hex.pm/running
* creating /root/.config
Mix LocalHex 0.5.5
四、安装 Node.js 22.x
Node.js 用于编译前端 assets(JavaScript + CSS)。Mindwendel 的前端使用 Phoenix LiveView HEEx 模板 + 少量 npm 包。
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version
npm --version
预期输出:
v22.14.0
10.8.2
五、源码获取与 Release 构建
5.1 克隆源码
cd /opt/mindwendel
sudo -u mindwendel git clone --depth 1 --branch v0.4.9-kits-1 https://github.com/kitsteam/mindwendel.git source
cd /opt/mindwendel/source
验证版本:
git log -1 --oneline
预期输出:
v0.4.9-kits-1... (commit hash)
5.2 安装 Mix 依赖
sudo -u mindwendel MIX_ENV=prod mix deps.get --only prod
预期输出(节选):
Resolving Hex dependencies...
Resolution completed in 0.146s
New:
backoff 1.1.3
castore 1.1.0
phoenix 1.7.18
phoenix_live_dashboard 0.8.10
phoenix_live_view 0.21.3
...
* Getting phoenix_live_view (Hex package)
Checking package (phoenix_live_view)
Fetched package
...
5.3 安装 npm 依赖并编译前端
sudo -u mindwendel -H bash -c 'export HOME=/opt/mindwendel && cd /opt/mindwendel/source/assets && npm install'
预期输出(节选):
added 235 packages, and audited 236 packages in 7s
...
npm notice found 0 vulnerabilities
5.4 编译前端 assets
sudo -u mindwendel MIX_ENV=prod mix assets.deploy
预期输出(节选):
Rebuilding...
Done in 1050ms.
...
Generated mindwendel app at /opt/mindwendel/source/_build/prod/rel/mindwendel
5.5 生成 Secret Key Base
SECRET_KEY_BASE=$(openssl rand -base64 48 | tr -d '\n')
echo $SECRET_KEY_BASE
预期输出(64 字符随机字符串):
aB3xY9kL2mN7pQ5rS8tU1vW4xZ6yA0bC2dE5fG7hJ9kL1nO4pQ6rS8tU0vW2xY4zA6bC8dE0fG
5.6 生成 Vault 加密密钥(文件附件加密用)
VAULT_ENCRYPTION_KEY_BASE64=$(openssl rand -base64 32)
echo $VAULT_ENCRYPTION_KEY_BASE64
5.7 构建 Release
sudo -u mindwendel MIX_ENV=prod mix release --overwrite
预期输出(节选):
==> Assembling release..
==> Building release mindwendel:0.4.9-kits-1 using environment prod
==> Release successfully built!
You can run it in one of the following ways:
Interactive: _build/prod/rel/mindwendel/bin/mindwendel console
Foreground: _build/prod/rel/mindwendel/bin/mindwendel foreground
Daemon: _build/prod/rel/mindwendel/bin/mindwendel start
六、配置生产环境变量
创建环境配置文件:
sudo mkdir -p /etc/mindwendel
sudo tee /etc/mindwendel/env > /dev/null <<'EOF'
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=mindwendel_prod
DATABASE_USER=mindwendel
DATABASE_USER_PASSWORD=q1w2e3r4
DATABASE_SSL=false
SECRET_KEY_BASE=aB3xY9kL2mN7pQ5rS8tU1vW4xZ6yA0bC2dE5fG7hJ9kL1nO4pQ6rS8tU0vW2xY4zA6bC8dE0fG
URL_HOST=your-domain.tld
URL_PORT=443
URL_SCHEME=https
MW_ENDPOINT_HTTP_PORT=4000
MW_DEFAULT_LOCALE=en
MW_FEATURE_BRAINSTORMING_REMOVAL_AFTER_DAYS=30
MW_FEATURE_IDEA_FILE_UPLOAD=false
VAULT_ENCRYPTION_KEY_BASE64=base64_encoded_32_bytes_here
EOF
sudo chown -R mindwendel:mindwendel /etc/mindwendel
sudo chmod 600 /etc/mindwendel/env
⚠️ 安全提示:如果开启文件附件上传(MW_FEATURE_IDEA_FILE_UPLOAD=true),必须额外配置 OBJECT_STORAGE_* 系列环境变量(见 C1 配置详解)。生产环境建议使用 MinIO 或其他 S3 兼容服务,不要用 rustfs 作为外部可访问的存储。
七、数据库迁移
export $(grep -v '^#' /etc/mindwendel/env | xargs)
sudo -u mindwendel -H bash -c "export HOME=/opt/mindwendel && MIX_ENV=prod DATABASE_HOST=localhost DATABASE_PORT=5432 DATABASE_NAME=mindwendel_prod DATABASE_USER=mindwendel DATABASE_USER_PASSWORD=q1w2e3r4 DATABASE_SSL=false SECRET_KEY_BASE=${SECRET_KEY_BASE} /opt/mindwendel/source/_build/prod/rel/mindwendel/bin/mindwendel eval 'Mindwendel.Release.migrate'"
预期输出:
... migrated: 20250215000001_create_brainstormings
... migrated: 20250215000002_create_ideas
... migrated: 20250215000003_create_labels
... migrated: 20250215000004_create_lanes
... migrated: 20250215000005_create_comments
... migrated: 20250215000006_create_users
... migrated: 20250215000007_create_file_attachments
💡 注意:Mindwendel 使用 Ecto 的 release migration 机制,
Mindwendel.Release.migrate会执行所有待执行的数据库迁移。这个命令只需要在首次部署或升级后运行一次。
八、配置 Systemd 服务
创建 systemd unit 文件:
sudo tee /etc/systemd/system/mindwendel.service > /dev/null <<'EOF'
[Unit]
Description=Mindwendel (Phoenix LiveView Brainstorming)
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=mindwendel
Group=mindwendel
EnvironmentFile=/etc/mindwendel/env
WorkingDirectory=/opt/mindwendel/source/_build/prod/rel/mindwendel
ExecStart=/opt/mindwendel/source/_build/prod/rel/mindwendel/bin/mindwendel start
ExecStop=/opt/mindwendel/source/_build/prod/rel/mindwendel/bin/mindwendel stop
Restart=on-failure
RestartSec=5
# 内存保护: 限制 OTP 进程数
LimitNPROC=65536
# 安全加固
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mindwendel
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
重载 systemd 并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable mindwendel
sudo systemctl start mindwendel
sudo systemctl status mindwendel
预期输出(节选):
● mindwendel.service - Mindwendel (Phoenix LiveView Brainstorming)
Loaded: loaded (/etc/systemd/system/mindwendel.service; enabled; vendor preset: enabled)
Active: active (running) since ...; 3s ago
Main PID: 28471 (mindwendel)
Tasks: 36 (limit: 15375)
Memory: 342.4M
...
九、验证
9.1 端口监听
ss -ltn | grep 4000
预期输出:
LISTEN 0 511 0.0.0.0:4000
9.2 HTTP 健康检查
curl -sI http://localhost:4000/ | head -5
预期输出:
HTTP/1.1 200 OK
server: Cowboy
date: ...
content-type: text/html; charset=utf-8
cache-control: max-age=0, private, must-revalidate
9.3 LiveView 连接测试
使用 WebSocket 客户端验证 LiveView 连接:
# 安装 websocat 如果可用,或使用 python websockets
curl -s -o /dev/null -w "%{http_code}" "http://localhost:4000/brainstorming/new"
预期输出:
200
9.4 Erlang 运行状态检查
sudo -u mindwendel /opt/mindwendel/source/_build/prod/rel/mindwendel/bin/mindwendel remote
进入 iex 后:
:application.which_applications() |> List.first()
MindwendelWeb.Endpoint.status()
Mindwendel.Repo.query("SELECT count(*) FROM schema_migrations;", [])
预期输出:
{:mindwendel, "Mindwendel", "0.4.9-kits-1"}
{:ok, _}
退出 iex:按 Ctrl+C 两次。
9.5 浏览器端验证
在浏览器访问 http://服务器IP:4000,应该看到 Mindwendel 的首页"Create a challenge. Ready? Brainstorm.",点击"Start brainstorming"创建一个新的头脑风暴,输入挑战题后进入协作界面。
十、配置 Nginx 反向代理(生产推荐)
Mindwendel 运行在 4000 端口,生产环境建议用 Nginx 做反向代理 + SSL 终止。
10.1 安装 Nginx
sudo apt-get install -y nginx
10.2 创建站点配置
sudo tee /etc/nginx/sites-available/mindwendel > /dev/null <<'NGINX'
server {
listen 80;
server_name your-domain.tld;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name your-domain.tld;
ssl_certificate /etc/letsencrypt/live/your-domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.tld/privkey.pem;
# LiveView WebSocket 关键配置
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
NGINX
sudo ln -sf /etc/nginx/sites-available/mindwendel /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
⚠️ 重要:
proxy_read_timeout 86400s和proxy_send_timeout 86400s是 LiveView WebSocket 长连接的关键配置——Nginx 默认 60 秒超时会断开 LiveView 连接。Upgrade和Connectionheader 是 WebSocket 握手必需的。
十一、升级与维护
升级流程
# 1. 停止服务
sudo systemctl stop mindwendel
# 2. 拉新代码
cd /opt/mindwendel/source
sudo -u mindwendel git fetch --tags
sudo -u mindwendel git checkout <new-tag>
# 3. 重新构建
sudo -u mindwendel MIX_ENV=prod mix deps.get --only prod
sudo -u mindwendel -H bash -c 'export HOME=/opt/mindwendel && cd /opt/mindwendel/source/assets && npm install'
sudo -u mindwendel MIX_ENV=prod mix assets.deploy
sudo -u mindwendel MIX_ENV=prod mix release --overwrite
# 4. 数据库迁移
export $(grep -v '^#' /etc/mindwendel/env | xargs)
sudo -u mindwendel -H bash -c "export HOME=/opt/mindwendel && /opt/mindwendel/source/_build/prod/rel/mindwendel/bin/mindwendel eval 'Mindwendel.Release.migrate'"
# 5. 启动服务
sudo systemctl start mindwendel
日志查看
sudo journalctl -u mindwendel -f
十二、常见问题排查
数据库连接失败
=ERROR= GenServer #PID<0.1234.0> terminating
** (DBConnection.ConnectionError) connection refused
检查 DATABASE_HOST / DATABASE_USER_PASSWORD 是否正确,PostgreSQL 是否运行:
sudo systemctl status postgresql
sudo -u postgres psql -h localhost -U mindwendel -d mindwendel_prod -c "SELECT 1;"
内存不足导致编译失败
memory allocation of 16777216 bytes failed
增加 swap 或调整内存限制:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
LiveView 连接断开
检查 Nginx 的 proxy_read_timeout 和 proxy_send_timeout 是否设置足够长(≥ 86400s)。如果没有反代,检查 Mindwendel 服务的 POOL_SIZE 配置(默认 10,高并发场景建议 ≥ 50)。