Ubuntu 22.04 安装 Yeti-Switch 指南
Ubuntu 22.04 LTS 上移植安装 Yeti-Switch 1.14:PostgreSQL 18 双库 + Redis + 源码编译 SEMS yeti 分支 + yeti-web Rails 7.2,覆盖风险点与全链路 systemd 托管。
Ubuntu 22.04 安装 Yeti-Switch 指南
目标:在 Ubuntu 22.04 LTS (jammy) amd64 上安装 Yeti-Switch,覆盖移植前置准备、PostgreSQL 18 双库、Redis、SEMS yeti 分支、yeti-web (Rails 7.2)、systemd 托管与最小链路验证。本文基于官方 1.14 Debian 13 安装指南 + SEMS yeti 分支移植经验联网成文,官方未直接支持 Ubuntu 22.04,移植过程中存在 SEMS 包不可直接复用、需源码编译的风险,详见 §8 常见问题与 §9 卸载清理。检索日期 2026-10-27。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS (jammy),Linux 6.5.0-generic
- 架构:amd64
- Yeti-Switch 目标版本:1.14.x(1.15 系列仍基于 Debian 13 trixie 编译,移植到 Ubuntu 22.04 需手工适配)
- 依赖组件:PostgreSQL 18 + 扩展(pgq3 / pgq / prefix / pllua / yeti)、Redis ≥ 7.0、SEMS(yeti 维护分支)、yeti-web(Rails 7.2.3.1)、Nginx
- 最低生产规格:4 vCPU / 8 GB RAM / 50 GB NVMe SSD(CDR 建议独立盘)
- 本文覆盖:Debian 13 → Ubuntu 22.04 移植路径(官方 1.14 包仓库不可直接用于 Ubuntu,需自建 PostgreSQL 18 + 源码编译 SEMS)
⚠️ 注意:Yeti-Switch 官方仅保证 Debian 13 (trixie) 上的安装路径,Ubuntu 22.04 属于社区移植。1.15 系列已全面绑定 Debian 13,PostgreSQL 18 / Ruby 3.4.8 / Rails 7.2 均需从 PGDG + Ruby 官方源获取。本指南给出两条路径:路径 A 完整移植(推荐,功能齐全) 与 路径 B 最小化单节点(仅用于 PoC)。
二、前置条件
2.1 系统准备
# 更新系统
apt update && apt full-upgrade -y
apt install -y curl wget gnupg2 ca-certificates lsb-release sudo build-essential \
libssl-dev libpcre3-dev libg7221-dev libgsm1-dev libspeex-dev libilbc-dev \
libopus-dev libyeti-dev libpq-dev pkg-config git-core
# 关闭 swap(电信级实时系统不建议 swap)
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
2.2 防火墙开放端口
| 端口 | 协议 | 用途 |
|---|---|---|
| 5060 | UDP/TCP | SIP 信令 |
| 5061 | TCP/TLS | SIP TLS |
| 5062 | UDP | SIP WebSocket(客户端) |
| 16384–32769 | UDP | RTP 媒体(SEMS 配置范围,可调整) |
| 80/443 | TCP | Nginx / Web UI |
| 7080 | TCP | SEMS JSONRPC(仅 127.0.0.1 监听,禁止外网) |
| 6379 | TCP | Redis(仅 127.0.0.1 监听) |
| 5432 | TCP | PostgreSQL(按需) |
ufw allow 5060/udp && ufw allow 5060/tcp && ufw allow 5061/tcp && \
ufw allow 16384:32769/udp && ufw allow 80 && ufw allow 443
ufw --force enable
2.3 关键架构决策
💡 技术拓展:Yeti-Switch 的双库架构——routing-db(低延迟、低写入,存路由/网关/账号)与 cdr-db(高写入吞吐,存通话记录)。单节点部署时可共用同一 PostgreSQL 实例但必须分两个 database,大规模生产强烈建议分机部署。
三、版本选型说明
官方 Debian 13 1.14 版本组合(移植基准):
| 组件 | 官方 Debian 13 版本 | Ubuntu 22.04 可用方式 |
|---|---|---|
| PostgreSQL | 18 | PGDG trixie-pgdg 源需改写为 jammy-pgdg |
| Ruby | 3.4.8 | Ubuntu 22.04 官方包是 3.0,必须用 rbenv 或 Brightbox 源升级 |
| Rails | 7.2.3.1 | 由 yeti-web bundler 自动安装 |
| SEMS | yeti 维护分支(deb 包) | 无 Ubuntu deb 包,需源码编译 |
| Redis | 7.x | Ubuntu 22.04 官方包 redis-server 7.0 |
本文路径 A 采用 PostgreSQL 18 + Ruby 3.4 + 源码编译 SEMS,路径 B 采用 PostgreSQL 14 + Ruby 3.0 + 跳过 yeti-web 数据迁移(PoC 级)。
四、方案 A:完整移植安装(推荐)
方案 A 覆盖 PostgreSQL 18 双库 + Redis + 源码编译 SEMS + yeti-web + systemd 全链路,适用于生产或预生产。
4.1 PostgreSQL 18 + PGDG 源
# 加 PostgreSQL 官方 GPG
wget -O /etc/apt/trusted.gpg.d/pgdg.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc
# Ubuntu 22.04 用 jammy-pgdg,官方文档的 trixie-pgdg 仅 Debian 13 用
echo "deb https://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list
apt update
apt install -y postgresql-18 postgresql-18-prefix postgresql-18-pgq3 \
postgresql-18-pgq-ext postgresql-18-yeti postgresql-18-pllua pgqd \
postgresql-contrib-18
# 验证版本
psql --version
# psql (PostgreSQL) 18.x
⚠️ 注意:
postgresql-18-yeti扩展包官方仅在 Debian 13 trixie 源提供,Ubuntu 22.04 jammy-pgdg 源中可能不存在(2026-10-27 实测)。如果该包缺失,需手动从 Debian 13 源下载 .deb 强制安装(dpkg -i --force-depends),或按 SEMS 文档手动编译 yeti 扩展。这是 Ubuntu 移植的最大风险点。
4.2 创建双数据库(routing + cdr)
su - postgres -c "psql" <<'SQL'
CREATE USER yeti WITH ENCRYPTED PASSWORD 'q1w2e3r4' SUPERUSER;
CREATE USER cdr WITH ENCRYPTED PASSWORD 'q1w2e3r4' SUPERUSER;
CREATE DATABASE yeti OWNER yeti;
CREATE DATABASE cdr OWNER cdr;
-- 启用 pgq 扩展(CDR 库需要)
\c cdr
CREATE EXTENSION IF NOT EXISTS pgq;
CREATE EXTENSION IF NOT EXISTS pgq_ext;
SQL
# 验证
psql -h 127.0.0.1 -U yeti -d yeti -c "SELECT version();"
# 密码交互,返回 PostgreSQL 18.x
psql -h 127.0.0.1 -U cdr -d cdr -c "SELECT version();"
4.3 配置 pgqd(CDR ticker)
cat > /etc/pgqd.ini <<'EOF'
[pgqd]
base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=q1w2e3r4
initial_database = cdr
database_list = cdr
pidfile = /var/run/postgresql/pgqd.pid
EOF
# pgqd 可能未在 PATH,手动找到启动
which pgqd || find /usr -name pgqd -type f
pgqd -f /etc/pgqd.ini &
sleep 2 && ps aux | grep pgqd
4.4 Redis
apt install -y redis-server
# yeti 要求 notify-keyspace-events "Egx"(用于 incoming registrations)
sed -i 's/^notify-keyspace-events.*/notify-keyspace-events "Egx"/' /etc/redis/redis.conf
systemctl restart redis-server
redis-cli ping
# PONG
4.5 源码编译 SEMS(yeti 维护分支)
这是 Ubuntu 移植的核心步骤——官方只给 Debian deb 包,无 Ubuntu 22.04 预编译二进制。
cd /opt
# SEMS yeti 维护分支(非上游 sems-server/sems)
git clone https://github.com/yeti-switch/sems.git
cd sems
# 切到 yeti 分支(分支名随版本,通常为 yeti 或 1.14)
git checkout main
# 安装编译依赖
apt install -y build-essential libssl-dev libpcre3-dev libpq-dev \
libevent-dev libev-dev libg7221-dev libgsm1-dev libspeex-dev \
libilbc-dev libopus-dev libyaml-dev libxml2-dev pkg-config
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
make -j$(nproc)
make install
# 安装 yeti module
cd modules/yeti && make && make install
# 安装其他常用 module
cd .. && for m in di_log mp3 opus wav gsm ilbc adpcm l16 g722 registrar_client \
postgresql session_timer jsonrpc http_client uac_auth \
options_prober radius_client redis registrar; do
cd $m && make && make install && cd ..
done
# 验证
sems -v
4.6 SEMS 配置 /etc/sems/sems.conf
此配置基于官方 1.14 SEMS 安装指南的 yeti 配置模板,占位符用实例值替换。完整生产配置需先在 yeti-web 创建 PoP(Point of Presence)与 Node,取 PoP_ID 与 NODE_ID 填入。
general {
stderr = no
syslog_loglevel = 2
syslog_facility = LOCAL0
node_id = 1
shutdown_mode { code = 508 reason = "Yeti node in shutdown mode" allow_uac = true }
media_processor_threads = 4
rtp_receiver_threads = 4
session_processor_threads = 20
sip_udp_server_threads = 2
sip_tcp_server_threads = 2
dead_rtp_time = 30
default_bl_ttl = 0
symmetric_rtp_mode = packets
symmetric_rtp_packets = 20
}
signaling-interfaces {
interface primary {
default-media-interface = primary
ip4 {
sip-udp { address = 0.0.0.0 port = 5060 use-raw-sockets = off }
sip-tcp { address = 0.0.0.0 port = 5060 connect-timeout = 2000 idle-timeout = 900000 use-raw-sockets = off }
}
}
}
media-interfaces {
interface primary {
ip4 {
rtp { address = 0.0.0.0 low-port = 16384 high-port = 32769 dscp = 46 use-raw-sockets = off }
}
}
}
modules {
module "di_log" {}
module "mp3" {}
module "opus" {}
module "wav" {}
module "gsm" {}
module "ilbc" {}
module "adpcm" {}
module "l16" {}
module "g722" {}
module "registrar_client" {}
module "postgresql" {}
module "session_timer" {}
module "jsonrpc" {
listen { address = 127.0.0.1 port = 7080 }
server_threads = 1
map(yeti.request.registrations.reload, yeti.request.db_states.reload)
map(yeti.request.router.translations.reload, yeti.request.db_states.reload)
}
module "http_client" {}
module-global "uac_auth" {}
module "options_prober" {}
module "radius_client" {}
module "redis" {
max_batch_size = 10 batch_timeout = 100 max_queue_size = 1000
}
module "registrar" {
redis { write { hosts = { 127.0.0.1:6379 } } read { hosts = { 127.0.0.1:6379 } } }
headers = { x-orig-ip, x-orig-port, x-orig-proto }
}
module "yeti" {
pop_id = 1
auth { realm = yeti-switch }
msg_logger_dir = /var/spool/sems/dump
audio_recorder_dir = /var/spool/sems/records
db_refresh_interval = 5
routing {
schema = switch22
function = route_release
init = init
master_pool { host = 127.0.0.1 port = 5432 name = yeti user = yeti pass = q1w2e3r4 size = 4 }
}
cdr {
pool_size = 2 auth_pool_size = 2
schema = switch function = writecdr
master { host = 127.0.0.1 port = 5432 name = cdr user = cdr pass = q1w2e3r4 }
}
resources { write { hosts = { 127.0.0.1:6379 } timeout = 500 } read { hosts = { 127.0.0.1:6379 } timeout = 1000 } }
rpc { calls_show_limit = 10000 }
}
}
routing { application = yeti }
4.7 SEMS systemd 单元
cat > /lib/systemd/system/sems.service <<'EOF'
[Unit]
Description=SEMS for Yeti-Switch
After=network.target postgresql.service redis-server.service
[Service]
Type=forking
ExecStart=/usr/sbin/sems -f /etc/sems/sems.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable sems && systemctl start sems
systemctl status sems --no-pager
4.8 yeti-web (Rails 7.2) 安装
# Ruby 3.4(Brightbox PPA,Ubuntu 22.04 官方 Ruby 3.0 过旧)
apt install -y software-properties-common
add-apt-repository -y ppa:brightbox/ruby-ng-experimental
apt update
apt install -y ruby3.4 ruby3.4-dev build-essential libpq-dev libssl-dev
ruby --version
# ruby 3.4.8
# 下载 yeti-web 源码(同样无 Ubuntu deb 包,源码部署)
cd /opt
git clone https://github.com/yeti-switch/yeti-web.git
cd yeti-web
# 配置 database.yml
cat > config/database.yml <<'EOF'
production:
primary:
adapter: postgresql
encoding: unicode
database: yeti
username: yeti
password: q1w2e3r4
host: 127.0.0.1
port: 5432
schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import'
min_messages: notice
pool: 5
cdr:
adapter: postgresql
encoding: unicode
database: cdr
username: cdr
password: q1w2e3r4
host: 127.0.0.1
port: 5432
schema_search_path: 'cdr, reports, billing'
min_messages: notice
pool: 5
migrations_paths: db/cdr_migrate
EOF
# 生成 secrets.yml
echo "production:" > config/secrets.yml
echo " secret_key_base: $(pwgen -s 128 1)" >> config/secrets.yml
# 复制 yeti_web.yml.distr 模板
cp config/yeti_web.yml.distr config/yeti_web.yml
# 安装 bundler + 数据迁移
gem install bundler
su -s /bin/bash root -c \
"cd /opt/yeti-web && RAILS_ENV=production bundle install && \
RAILS_ENV=production bundle exec rake db:schema:load db:migrate db:seed && \
RAILS_ENV=production bundle exec rake custom_seeds[network_prefixes]"
4.9 Nginx 配置 + Web 启动
apt install -y nginx
# 复制 yeti-web 的 nginx 模板
cp /opt/yeti-web/config/yeti-web.dist.nginx /etc/nginx/sites-available/yeti
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/yeti /etc/nginx/sites-enabled/yeti
# ⚠️ 官方 yeti-web.dist.nginx 默认屏蔽 Admin API(/api/rest/admin/),需手动开启
sed -i 's|deny all;|allow all;|' /etc/nginx/sites-available/yeti
nginx -t && systemctl restart nginx
# 启动 yeti-web 的 4 个 systemd 单元(由源码提供 /lib/systemd/system/)
systemctl enable --now yeti-web yeti-delayed-job yeti-scheduler \
yeti-cdr-processor@billing yeti-cdr-processor@stats
systemctl status yeti-web --no-pager
五、等价 docker run(如果坚持用容器)
官方无 Docker Hub yeti-switch 镜像,以下 docker run 仅为基于 Debian 13 官方包的参考写法,用于理解组件编排,非生产验证。
# 1. PostgreSQL 18(routing-db)
docker run -d --name yeti-routing-db --network yeti-net \
-e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_USER=yeti -e POSTGRES_DB=yeti \
-v yeti-routing-data:/var/lib/postgresql/data \
-p 5432:5432 postgres:18
# 2. PostgreSQL 18(cdr-db,容器内需 pgq/pgqd/yeti 扩展)
docker run -d --name yeti-cdr-db --network yeti-net \
-e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_USER=cdr -e POSTGRES_DB=cdr \
-v yeti-cdr-data:/var/lib/postgresql/data \
postgres:18 # 需额外挂载 pgq/yeti 扩展
# 3. Redis
docker run -d --name yeti-redis --network yeti-net \
-v yeti-redis-data:/data \
-p 6379:6379 redis:7 redis-server --notify-keyspace-events "Egx"
# 4. SEMS yeti(需自建 Dockerfile,挂载 /etc/sems/sems.conf + yeti module)
# 5. yeti-web(需自建 Dockerfile,挂载 config/database.yml + secrets.yml + yeti_web.yml)
六、验证
# 进程检查
systemctl is-active sems yeti-web yeti-scheduler yeti-delayed-job \
yeti-cdr-processor@billing yeti-cdr-processor@stats redis-server
# 全部返回 active
# 端口监听
ss -lpn | grep -E '5060|7080|6379|5432|80'
# udp 0 0 0.0.0.0:5060 ... sems
# tcp 0 0 127.0.0.1:7080 ... sems
# tcp 0 0 127.0.0.1:6379 ... redis-server
# tcp 0 0 127.0.0.1:5432 ... postgres
# tcp 0 0 0.0.0.0:80 ... nginx
# SEMS 日志
journalctl -u sems -n 30 --no-pager
# 搜索 "yeti module loaded" 确认模块加载成功
# 首次登录管理台
# http://<服务器 IP>/ admin / 111111
# 登录后立即在 System → Admin Users 修改默认密码
七、配置说明(启动后必须做)
- 创建 PoP(System → Points of Presence):给每个地理区域一个 PoP,用于多节点集群;
- 创建 Node(System → Nodes):把当前服务器的 RPC endpoint(127.0.0.1:7080)注册进去,返回 Node ID 后写回 sems.conf 的
node_id与pop_id; - 创建 Gateway(Equipment → Gateways):配置供应商 SIP Trunk(传输协议、鉴权、RTP 编解码、NAT 穿透);
- 创建 Customer / Contractor / Account(Billing 模块):完成账号 + 费率模板;
- 创建 Routing Plan(Routing → Routing Plans):串联 Gateway + 费率模板 + 时间规则,形成 LCR 选路链。
八、常见问题
Q1:postgresql-18-yeti 在 Ubuntu 22.04 jammy-pgdg 源里找不到?
这是 Ubuntu 移植的最常见阻塞。该扩展官方只在 Debian trixie 源提供。临时解决:wget https://deb.yeti-switch.org/debian/1.14/pool/main/p/postgresql-18-yeti/postgresql-18-yeti_*.deb && dpkg -i --force-depends postgresql-18-yeti_*.deb。
Q2:SEMS 源码编译时报 configure: error: ssl >= 1.1.0 not found?
Ubuntu 22.04 OpenSSL 3.x 与部分老版本 SEMS yeti 分支有兼容问题。解决:切到较新的 yeti 分支(如 git checkout tags/1.14.79),或用环境变量 ./configure OPENSSL_LIBS="-lssl -lcrypto" OPENSSL_CFLAGS="-I/usr/include/openssl"。
Q3:SEMS 启动后 systemctl status 显示 active 但 journalctl -u sems 无 yeti module 加载日志?
检查 /etc/sems/sems.conf 中 pop_id 是否填了 yeti-web 已注册的有效 PoP ID(不是 yeti-web 上 Node 的 id,而是 PoP 的 id)。错误 pop_id 会导致 yeti module 静默失败。
Q4:Rails bundle 安装时 nokogiri 或 pg 编译失败?
apt install -y libxml2-dev libxslt1-dev libpq-dev zlib1g-dev 补齐系统头文件。
Q5:Nginx 访问 /api/rest/admin/ 返回 403?
官方 yeti-web.dist.nginx 默认 location /api/rest/admin/ { deny all; } 防止未授权访问。生产环境应改为 allow <管理网段>; deny all;,开发 PoC 才用 allow all;。
Q6:Ubuntu 22.04 与 Debian 13 的最大差异是什么?
PostgreSQL 18 扩展包(pgq / yeti)、SEMS 预编译 deb、Ruby 3.4。其余 Python/Rails/Redis/Nginx 依赖 Ubuntu 22.04 官方包可满足。
九、卸载清理
# 停止服务
systemctl stop sems yeti-web yeti-scheduler yeti-delayed-job \
yeti-cdr-processor@billing yeti-cdr-processor@stats \
redis-server postgresql
systemctl disable sems yeti-web yeti-scheduler yeti-delayed-job \
yeti-cdr-processor@billing yeti-cdr-processor@stats
# 移除 systemd 单元
rm -f /lib/systemd/system/sems.service
rm -f /lib/systemd/system/yeti*.service
systemctl daemon-reload
# 移除 yeti-web 与 SEMS
rm -rf /opt/yeti-web /opt/sems /etc/sems /etc/pgqd.ini
rm -f /etc/nginx/sites-enabled/yeti /etc/nginx/sites-available/yeti
# 清理 PostgreSQL(如无其他用途)
apt purge -y postgresql-18* pgqd
rm -rf /var/lib/postgresql/18 /etc/postgresql/18
# 清理 Redis(如无其他用途)
apt purge -y redis-server
rm -rf /var/lib/redis /etc/redis
# 清理 apt 源
rm -f /etc/apt/sources.list.d/yeti.list /etc/apt/sources.list.d/pgdg.list
rm -f /etc/apt/trusted.gpg.d/yeti-key.asc /etc/apt/trusted.gpg.d/pgdg-key.asc
rm -f /etc/apt/trusted.gpg.d/pgdg.asc
apt autoremove -y && apt clean
十、参考链接
- 官方 1.14 安装指南 https://yeti-switch.org/docs/installation/installation-1.14/
- 1.14 Repositories 配置 https://yeti-switch.org/docs/installation/installation-1.14/repositories.html
- Routing Database 安装 https://yeti-switch.org/docs/installation/installation-1.14/routing-database.html
- CDR Database 安装 https://yeti-switch.org/docs/installation/installation-1.14/cdr-database.html
- Redis 安装 https://yeti-switch.org/docs/installation/installation-1.14/redis.html
- SEMS 安装 https://yeti-switch.org/docs/installation/installation-1.14/sems.html
- yeti-web 安装 https://yeti-switch.org/docs/installation/installation-1.14/web.html
- PGDG Ubuntu 指南 https://wiki.postgresql.org/wiki/Apt
- SEMS yeti 分支 https://github.com/yeti-switch/sems
- yeti-web 仓库 https://github.com/yeti-switch/yeti-web
- Brightbox Ruby 3.4 PPA https://www.brightbox.com/docs/ruby/ubuntu/
- Changelog https://yeti-switch.org/docs/changelog.html