837 lines
24 KiB
Markdown
837 lines
24 KiB
Markdown
# OpenSIPS installation notes
|
||
|
||
中文说明:OpenSIPS 安装与修复备忘。
|
||
|
||
This file records the installation performed on workstation `100.93.185.30`
|
||
and the missing pieces found afterwards. Use `install-opensips-stack.sh` for a
|
||
repeatable production install.
|
||
|
||
中文说明:这个文件记录了 `100.93.185.30` 工作站上的安装过程、后来补齐的缺失模块,以及生产环境一键安装时应复用的脚本。
|
||
|
||
## Target stack
|
||
|
||
中文说明:目标软件栈。
|
||
|
||
- OS: Ubuntu 24.04 Noble
|
||
- OpenSIPS: 3.6.x from `https://apt.opensips.org`
|
||
- OpenSIPS Control Panel: 9.3.6
|
||
- RTPengine: Ubuntu `rtpengine-daemon`
|
||
- Database: MariaDB
|
||
- Web server: Apache + PHP
|
||
|
||
## Production one-shot install
|
||
|
||
中文说明:生产环境一键安装方式。
|
||
|
||
Copy `install-opensips-stack.sh` to a fresh Ubuntu 24.04 server and run:
|
||
|
||
中文说明:把 `install-opensips-stack.sh` 拷贝到一台全新的 Ubuntu 24.04 服务器上,然后执行下面命令。
|
||
|
||
```bash
|
||
sudo -E SIP_IP=YOUR_SERVER_IP DB_PASS='CHANGE_ME' bash install-opensips-stack.sh
|
||
```
|
||
|
||
Useful variables:
|
||
|
||
中文说明:下面这些环境变量可以按生产环境修改,例如服务器 IP、数据库密码、MI 端口、RTPengine 端口范围、Monit 账号等。
|
||
|
||
```bash
|
||
SIP_IP=100.93.185.30
|
||
SIP_DOMAIN=100.93.185.30
|
||
DB_NAME=opensips
|
||
DB_USER=opensips
|
||
DB_PASS=opensipsrw
|
||
CP_VERSION=9.3.6
|
||
MI_HTTP_IP=127.0.0.1
|
||
MI_HTTP_PORT=8888
|
||
RTPENGINE_NG=127.0.0.1:2223
|
||
RTPENGINE_PORT_MIN=30000
|
||
RTPENGINE_PORT_MAX=40000
|
||
MONIT_IP=127.0.0.1
|
||
MONIT_PORT=2812
|
||
MONIT_USER=admin
|
||
MONIT_PASS=monit
|
||
```
|
||
|
||
After installation:
|
||
|
||
中文说明:安装完成后,OpenSIPS-CP 管理页面和默认账号如下。
|
||
|
||
```text
|
||
OpenSIPS-CP: http://YOUR_SERVER_IP/cp/
|
||
Default user: admin
|
||
Default pass: opensips
|
||
```
|
||
|
||
Change the OpenSIPS-CP admin password before production use.
|
||
|
||
中文说明:生产环境必须修改 OpenSIPS-CP 默认管理员密码,避免后台被默认口令登录。
|
||
|
||
## Startup and boot enablement
|
||
|
||
中文说明:服务启动和开机自启。
|
||
|
||
OpenSIPS itself is a systemd service:
|
||
|
||
中文说明:OpenSIPS 本体是 systemd 服务,下面命令用于设置开机自启、重启、查看是否运行和是否启用。
|
||
|
||
```bash
|
||
sudo systemctl enable opensips
|
||
sudo systemctl restart opensips
|
||
systemctl is-active opensips
|
||
systemctl is-enabled opensips
|
||
```
|
||
|
||
Expected result:
|
||
|
||
中文说明:期望看到 `active` 和 `enabled`,表示服务正在运行并已设置开机启动。
|
||
|
||
```text
|
||
active
|
||
enabled
|
||
```
|
||
|
||
OpenSIPS-CP is the web control panel at:
|
||
|
||
中文说明:OpenSIPS-CP 是 Web 管理后台,通过 `/cp/` 访问。
|
||
|
||
```text
|
||
http://YOUR_SERVER_IP/cp/
|
||
```
|
||
|
||
It is served by Apache and uses MariaDB, so there is no separate
|
||
`opensips-cp.service` to enable. Enable and start these services instead:
|
||
|
||
中文说明:OpenSIPS-CP 不是独立服务,它依赖 Apache 提供网页、MariaDB 存配置和数据,所以要启用的是 `apache2` 和 `mariadb`。
|
||
|
||
```bash
|
||
sudo systemctl enable apache2 mariadb
|
||
sudo systemctl restart mariadb
|
||
sudo systemctl restart apache2
|
||
systemctl is-active apache2 mariadb
|
||
systemctl is-enabled apache2 mariadb
|
||
```
|
||
|
||
Expected result:
|
||
|
||
```text
|
||
active
|
||
active
|
||
enabled
|
||
enabled
|
||
```
|
||
|
||
Useful verification commands:
|
||
|
||
中文说明:下面命令用于确认 SIP 端口、Web 端口、CP 页面和 MI HTTP 接口都正常。
|
||
|
||
```bash
|
||
ss -lunp | grep ':5060'
|
||
ss -ltnp | grep ':80'
|
||
curl -fsSI http://127.0.0.1/cp/
|
||
curl -fsS -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"ps"}'
|
||
```
|
||
|
||
On the current workstation, the public access URL is:
|
||
|
||
中文说明:当前这台工作站的访问地址如下。
|
||
|
||
```text
|
||
http://100.93.185.30/cp/
|
||
```
|
||
|
||
## Packages that must not be missed
|
||
|
||
中文说明:容易漏装但必须安装的软件包。
|
||
|
||
Base OpenSIPS packages:
|
||
|
||
中文说明:OpenSIPS 主程序、CLI、MySQL、认证和 TLS 相关基础包。
|
||
|
||
```bash
|
||
opensips
|
||
opensips-cli
|
||
opensips-mysql-module
|
||
opensips-auth-modules
|
||
opensips-tls-module
|
||
```
|
||
|
||
Database schema package:
|
||
|
||
中文说明:OpenSIPS 数据库建表脚本包。
|
||
|
||
```bash
|
||
opensips-mysql-dbschema
|
||
```
|
||
|
||
This one is easy to miss. Without it, `/usr/share/opensips/mysql/*.sql` is not
|
||
available and `opensipsdbctl` may not exist on OpenSIPS 3.6 installs.
|
||
|
||
中文说明:这个包很容易漏。没有它就找不到 `/usr/share/opensips/mysql/*.sql`,后续建表和导入模块表会很麻烦。
|
||
|
||
OpenSIPS-CP MI support:
|
||
|
||
中文说明:OpenSIPS-CP 通过 MI 接口控制 OpenSIPS,下面两个包提供 HTTP MI 和 JSON 支持。
|
||
|
||
```bash
|
||
opensips-http-modules
|
||
opensips-json-module
|
||
```
|
||
|
||
These provide `httpd.so`, `mi_http.so` and JSON support. Without them,
|
||
OpenSIPS-CP actions such as `Reload on Server` will fail when configured for
|
||
`json:127.0.0.1:8888/mi`.
|
||
|
||
中文说明:没有这些模块时,CP 页面里的 `Reload on Server` 会连不上 `127.0.0.1:8888/mi` 或提示 MI 命令不可用。
|
||
|
||
SIP user authentication and database registration:
|
||
|
||
中文说明:SIP 用户认证和注册落库需要的模块。
|
||
|
||
```bash
|
||
opensips-auth-modules
|
||
opensips-mysql-module
|
||
```
|
||
|
||
Enable these modules in `opensips.cfg`:
|
||
|
||
中文说明:在 `opensips.cfg` 中启用认证模块和位置服务模块,让用户可以用数据库账号注册到 OpenSIPS。
|
||
|
||
```opensips
|
||
loadmodule "auth.so"
|
||
loadmodule "auth_db.so"
|
||
modparam("auth_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("auth_db", "calculate_ha1", 1)
|
||
|
||
loadmodule "usrloc.so"
|
||
modparam("usrloc", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("usrloc", "working_mode_preset", "single-instance-sql-write-through")
|
||
```
|
||
|
||
Then protect REGISTER requests:
|
||
|
||
中文说明:下面这段用于保护 REGISTER 请求;没有正确账号密码的终端不能注册。
|
||
|
||
```opensips
|
||
if (is_method("REGISTER")) {
|
||
if (!www_authorize("$fd", "subscriber")) {
|
||
www_challenge("$fd", "auth");
|
||
exit;
|
||
}
|
||
|
||
if (!save("location"))
|
||
xlog("failed to register AoR $tu\n");
|
||
|
||
exit;
|
||
}
|
||
```
|
||
|
||
`calculate_ha1=1` lets OpenSIPS calculate the digest hash from the plain
|
||
`subscriber.password` column created by OpenSIPS-CP.
|
||
|
||
中文说明:`calculate_ha1=1` 表示 OpenSIPS 可以根据 `subscriber.password` 明文密码计算 SIP Digest 认证需要的 hash。
|
||
|
||
Dialog tracking for the OpenSIPS-CP Dialog page:
|
||
|
||
中文说明:Dialog 页面用于查看在线通话/会话状态,需要启用 `dialog.so`。
|
||
|
||
```opensips
|
||
loadmodule "dialog.so"
|
||
modparam("dialog", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("dialog", "profiles_no_value", "inbound;outbound")
|
||
modparam("dialog", "profiles_with_value", "caller;callee")
|
||
```
|
||
|
||
Create dialog state for initial INVITEs:
|
||
|
||
中文说明:初始 INVITE 到来时创建 dialog 状态,并把主叫、被叫等信息放进 profile,便于 CP 页面查看。
|
||
|
||
```opensips
|
||
if (is_method("INVITE")) {
|
||
create_dialog();
|
||
set_dlg_profile("outbound");
|
||
set_dlg_profile("caller", "$fU");
|
||
set_dlg_profile("callee", "$rU");
|
||
do_accounting("log");
|
||
}
|
||
```
|
||
|
||
Without `dialog.so`, OpenSIPS-CP Dialog pages fail with:
|
||
|
||
中文说明:如果没加载 `dialog.so`,Dialog 页面会报下面这个 MI 方法不存在。
|
||
|
||
```text
|
||
MI command failed with code -32601 (Method not found)
|
||
```
|
||
|
||
Validation:
|
||
|
||
中文说明:验证 Dialog MI 命令是否可用。
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"dlg_list"}'
|
||
```
|
||
|
||
Dispatcher support for the OpenSIPS-CP Dispatcher page:
|
||
|
||
中文说明:Dispatcher 页面用于管理/查看后端服务器分发列表,需要启用 `dispatcher.so`。
|
||
|
||
```opensips
|
||
loadmodule "dispatcher.so"
|
||
modparam("dispatcher", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("dispatcher", "persistent_state", 1)
|
||
```
|
||
|
||
Without `dispatcher.so`, OpenSIPS-CP Dispatcher pages fail with:
|
||
|
||
中文说明:如果没加载 `dispatcher.so`,Dispatcher 页面会报下面这个 MI 方法不存在。
|
||
|
||
```text
|
||
MI command failed with code -32601 (Method not found)
|
||
```
|
||
|
||
Validation:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"ds_list"}'
|
||
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":2,"method":"ds_reload"}'
|
||
```
|
||
|
||
Dynamic Routing support for the OpenSIPS-CP Dashboard and Dynamic Routing pages:
|
||
|
||
中文说明:Dynamic Routing 是动态路由/LCR 能力,用于管理落地网关、路由规则、网关状态,也支撑 Dashboard 的动态路由小组件。
|
||
|
||
```opensips
|
||
loadmodule "drouting.so"
|
||
modparam("drouting", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("drouting", "drd_table", "dr_gateways")
|
||
modparam("drouting", "drr_table", "dr_rules")
|
||
modparam("drouting", "drg_table", "dr_groups")
|
||
modparam("drouting", "drc_table", "dr_carriers")
|
||
```
|
||
|
||
The Dashboard `Dynamic Routing` widget calls MI commands such as
|
||
`dr_gw_status` and `dr_reload_status`. Without `drouting.so`, Dashboard may show:
|
||
|
||
中文说明:Dashboard 上的 `Dynamic Routing` 卡片会调用 `dr_gw_status` 等命令;如果没加载 `drouting.so`,Dashboard 会出现 Method not found。
|
||
|
||
```text
|
||
MI command failed with code -32601 (Method not found)
|
||
```
|
||
|
||
Validation:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"dr_gw_status"}'
|
||
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":2,"method":"dr_reload_status"}'
|
||
```
|
||
|
||
On a fresh system with no dynamic-routing gateways configured, `dr_gw_status`
|
||
should return an empty `Gateways` list, not `Method not found`.
|
||
|
||
中文说明:新系统没有配置网关时,返回空网关列表是正常的;错误是 `Method not found`,说明模块没加载。
|
||
|
||
RTPengine:
|
||
|
||
中文说明:RTPengine 是媒体代理,负责 RTP 媒体流转发、NAT 穿透,也可配合录音。
|
||
|
||
```bash
|
||
rtpengine-daemon
|
||
```
|
||
|
||
OpenSIPS-CP has two separate media relay pages:
|
||
|
||
中文说明:OpenSIPS-CP 里 RTPProxy 和 RTPEngine 是两个不同页面,分别对应不同 OpenSIPS 模块。
|
||
|
||
- `RTPProxy` uses the OpenSIPS `rtpproxy.so` module and MI commands such as
|
||
`rtpproxy_show`, `rtpproxy_reload`, and `rtpproxy_enable`.
|
||
- `RTPEngine` uses the OpenSIPS `rtpengine.so` module and MI commands such as
|
||
`rtpengine_show`, `rtpengine_reload`, and `rtpengine_enable`.
|
||
|
||
If either module is not loaded, its page fails with:
|
||
|
||
中文说明:对应模块没加载时,页面会报 MI 命令不存在。
|
||
|
||
```text
|
||
MI command failed with code -32601 (Method not found)
|
||
```
|
||
|
||
For this workstation, RTPengine is the actual media proxy daemon. RTPProxy is
|
||
loaded only so the OpenSIPS-CP RTPProxy page can call its MI commands; without
|
||
RTPProxy sockets configured, the page should show an empty list instead of a
|
||
Method not found error.
|
||
|
||
中文说明:当前工作站实际使用的是 RTPengine。RTPProxy 模块只是为了让 CP 的 RTPProxy 页面不报错;没有配置 RTPProxy socket 时显示空列表是正常的。
|
||
|
||
OpenSIPS module config:
|
||
|
||
中文说明:下面配置同时启用 `rtpengine.so` 和 `rtpproxy.so`,分别对应两个 CP 页面。
|
||
|
||
```opensips
|
||
loadmodule "rtpengine.so"
|
||
modparam("rtpengine", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("rtpengine", "db_table", "rtpengine")
|
||
|
||
loadmodule "rtpproxy.so"
|
||
modparam("rtpproxy", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("rtpproxy", "db_table", "rtpproxy_sockets")
|
||
```
|
||
|
||
RTPengine DB row used on the current workstation:
|
||
|
||
中文说明:当前工作站的 RTPengine 控制 socket 是 `udp:127.0.0.1:2223`,需要写入 `rtpengine` 表。
|
||
|
||
```sql
|
||
INSERT INTO rtpengine (socket, set_id)
|
||
SELECT 'udp:127.0.0.1:2223', 0
|
||
WHERE NOT EXISTS (
|
||
SELECT 1 FROM rtpengine WHERE socket='udp:127.0.0.1:2223' AND set_id=0
|
||
);
|
||
```
|
||
|
||
Validation:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"rtpengine_show"}'
|
||
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":2,"method":"rtpproxy_show"}'
|
||
```
|
||
|
||
## OpenSIPS-CP SIP Trace page
|
||
|
||
中文说明:OpenSIPS-CP 的 SIP Trace 页面。
|
||
|
||
The SIP Trace page displays SIP messages captured by OpenSIPS and stored in the
|
||
`sip_trace` table. It is useful for troubleshooting registration, INVITE call
|
||
setup, routing, authentication challenges, and failed SIP responses. It lets
|
||
you filter by:
|
||
|
||
中文说明:SIP Trace 用于查看 OpenSIPS 抓到的 SIP 报文,适合排查注册失败、呼叫不通、路由错误、认证失败和 SIP 响应异常。
|
||
|
||
- `RegExp`: text or regex to search in captured SIP messages.
|
||
- `Call ID`: one SIP dialog/transaction identifier.
|
||
- `Traced User`: the trace attribute saved by the script, here `$fU`.
|
||
- `Start Date` / `End Date`: time range.
|
||
- `Group results by Call ID`: groups multiple SIP messages from the same call.
|
||
|
||
If the page shows:
|
||
|
||
中文说明:如果 SIP Trace 页面出现下面的错误,说明 `trace` MI 命令不存在。
|
||
|
||
```text
|
||
MI command failed with code -32601 (Method not found)
|
||
```
|
||
|
||
then OpenSIPS-CP called the `trace` MI command, but OpenSIPS did not load the
|
||
`tracer.so` module.
|
||
|
||
中文说明:原因是 CP 调用了 `trace` 命令,但 OpenSIPS 没加载 `tracer.so`。
|
||
|
||
OpenSIPS module config:
|
||
|
||
中文说明:下面配置开启 tracer 模块,并把 trace 数据写入 MySQL 的 `sip_trace` 表。
|
||
|
||
```opensips
|
||
loadmodule "tracer.so"
|
||
modparam("tracer", "trace_on", 1)
|
||
modparam("tracer", "trace_id", "[tid]uri=mysql://opensips:opensipsrw@localhost/opensips;table=sip_trace;")
|
||
```
|
||
|
||
Main route hook used on the current workstation:
|
||
|
||
中文说明:仅启用模块还不会自动写入数据,路由脚本里需要调用 `trace()`。
|
||
|
||
```opensips
|
||
route{
|
||
trace("tid", "m", "sip", "$fU");
|
||
```
|
||
|
||
The `trace` MI command only toggles tracing on/off. The `trace()` call in the
|
||
routing script is what actually writes messages to the `sip_trace` database
|
||
table.
|
||
|
||
中文说明:MI 的 `trace` 命令只是开关;真正把 SIP 消息写进数据库的是路由脚本中的 `trace()` 函数。
|
||
|
||
Validation:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"trace"}'
|
||
|
||
mysql -D opensips -e "SELECT COUNT(*) FROM sip_trace;"
|
||
```
|
||
|
||
SIP Trace can grow quickly on a busy server. In production, keep it disabled by
|
||
default or clean old rows regularly.
|
||
|
||
中文说明:生产环境要谨慎开启 SIP Trace,因为话务量大时 `sip_trace` 表会增长很快,应定期清理或只在排障时开启。
|
||
|
||
Web/database dependencies:
|
||
|
||
中文说明:Web 前端和数据库依赖包。
|
||
|
||
```bash
|
||
mariadb-server mariadb-client
|
||
apache2 libapache2-mod-php
|
||
php php-cli php-mysql php-gd php-pear php-apcu php-curl php-xml php-mbstring
|
||
git unzip curl
|
||
```
|
||
|
||
Monit support for the OpenSIPS-CP Monit page:
|
||
|
||
中文说明:Monit 页面用于查看服务器服务和系统状态,需要安装 `monit`。
|
||
|
||
```bash
|
||
monit
|
||
```
|
||
|
||
OpenSIPS-CP's Monit page is a proxy to Monit's own HTTP interface. If `monit`
|
||
is not installed or the OpenSIPS-CP box has no `monit_conn`, the page may show:
|
||
|
||
中文说明:CP 的 Monit 页面实际是代理访问 Monit 自带 HTTP 页面;如果 Monit 没装或 CP 的 box 没配置 `monit_conn`,就会报空地址。
|
||
|
||
```text
|
||
Failed to parse address ""
|
||
Error: 1
|
||
I can't connect!
|
||
```
|
||
|
||
Configure Monit to listen locally:
|
||
|
||
中文说明:Monit 只监听本机 `127.0.0.1:2812`,避免暴露到外网。
|
||
|
||
```monit
|
||
set httpd port 2812 and
|
||
use address 127.0.0.1
|
||
allow 127.0.0.1
|
||
allow admin:monit
|
||
```
|
||
|
||
Enable it:
|
||
|
||
```bash
|
||
sudo monit -t
|
||
sudo systemctl enable monit
|
||
sudo systemctl restart monit
|
||
```
|
||
|
||
Configure the OpenSIPS-CP default box:
|
||
|
||
中文说明:把 OpenSIPS-CP 默认 box 的 Monit 连接地址、账号和密码写入数据库。
|
||
|
||
```sql
|
||
UPDATE ocp_boxes_config
|
||
SET monit_conn='127.0.0.1:2812',
|
||
monit_user='admin',
|
||
monit_pass='monit',
|
||
monit_ssl=0
|
||
WHERE id=1;
|
||
```
|
||
|
||
Validation:
|
||
|
||
```bash
|
||
systemctl is-active monit
|
||
systemctl is-enabled monit
|
||
ss -ltnp | grep ':2812'
|
||
curl -fsS -u admin:monit http://127.0.0.1:2812/ | grep -m1 Monit
|
||
```
|
||
|
||
On the current workstation, Monit is installed, enabled, and bound to
|
||
`127.0.0.1:2812`. The OpenSIPS-CP default box uses `admin` / `monit`.
|
||
|
||
中文说明:当前工作站已经安装并启用 Monit,CP 使用 `admin / monit` 连接本机 Monit。生产环境请修改密码。
|
||
|
||
## OpenSIPS config added during the fix
|
||
|
||
中文说明:安装后补加到 OpenSIPS 配置里的关键修复项。
|
||
|
||
The initial installation only had `mi_fifo`. OpenSIPS-CP was configured to call:
|
||
|
||
中文说明:最初只有 `mi_fifo`,但 CP 配置的是 JSON HTTP MI,所以页面 reload 会失败。
|
||
|
||
```text
|
||
json:127.0.0.1:8888/mi
|
||
```
|
||
|
||
So `Reload on Server` failed with:
|
||
|
||
中文说明:因此 CP 页面点击 `Reload on Server` 时会连接不上 8888 端口。
|
||
|
||
```text
|
||
Failed to connect to 127.0.0.1 port 8888
|
||
```
|
||
|
||
The fix was to load HTTP MI:
|
||
|
||
中文说明:修复方法是加载 `httpd.so` 和 `mi_http.so`,让 OpenSIPS 提供本地 HTTP MI 接口。
|
||
|
||
```opensips
|
||
loadmodule "httpd.so"
|
||
modparam("httpd", "ip", "127.0.0.1")
|
||
modparam("httpd", "port", 8888)
|
||
|
||
loadmodule "mi_http.so"
|
||
modparam("mi_http", "root", "mi")
|
||
```
|
||
|
||
After that, the MI endpoint worked, but `address_reload` returned:
|
||
|
||
中文说明:HTTP MI 通了以后,`address_reload` 又报方法不存在,这是因为还没加载权限模块。
|
||
|
||
```text
|
||
Method not found
|
||
```
|
||
|
||
That command is provided by `permissions.so`, so the next fix was:
|
||
|
||
中文说明:`address_reload` 由 `permissions.so` 提供,所以需要加载 permissions 模块并配置数据库。
|
||
|
||
```opensips
|
||
loadmodule "db_mysql.so"
|
||
|
||
loadmodule "permissions.so"
|
||
modparam("permissions", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("permissions", "address_table", "address")
|
||
```
|
||
|
||
Validation command:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"address_reload"}'
|
||
```
|
||
|
||
Expected result:
|
||
|
||
中文说明:期望返回 OK。
|
||
|
||
```json
|
||
{"jsonrpc":"2.0","result":"OK","id":1}
|
||
```
|
||
|
||
## OpenSIPS-CP Addresses page
|
||
|
||
中文说明:OpenSIPS-CP 的 Addresses 页面。
|
||
|
||
The Addresses page writes to the `address` table used by the `permissions`
|
||
module.
|
||
|
||
中文说明:Addresses 页面配置的是 IP 访问规则/白名单类规则,写入 `permissions` 模块使用的 `address` 表。
|
||
|
||
It is not where the local OpenSIPS listening IP is configured. The listening IP
|
||
belongs in:
|
||
|
||
中文说明:这里不是配置 OpenSIPS 本机监听 IP 的地方;本机监听 IP 要写在 `opensips.cfg` 的 `socket`。
|
||
|
||
```text
|
||
/etc/opensips/opensips.cfg
|
||
```
|
||
|
||
Example:
|
||
|
||
```opensips
|
||
socket=udp:100.93.185.30:5060
|
||
```
|
||
|
||
Typical Address entry:
|
||
|
||
中文说明:典型地址规则示例如下。
|
||
|
||
```text
|
||
Group: 1
|
||
IP: 47.97.162.65
|
||
Mask: 32
|
||
Port: 5060
|
||
Protocol: any
|
||
Pattern:
|
||
Context Info: lisglo
|
||
```
|
||
|
||
Notes:
|
||
|
||
中文说明:字段注意事项。
|
||
|
||
- `Group` must be numeric.
|
||
- `Pattern` is an optional wildcard pattern used by `permissions` matching.
|
||
- `Context Info` is returned to the OpenSIPS script when the rule matches.
|
||
- Click `Reload on Server` after editing Addresses.
|
||
|
||
## OpenSIPS-CP Domains validation issue
|
||
|
||
中文说明:OpenSIPS-CP Domains 页面表单校验问题。
|
||
|
||
On OpenSIPS-CP 9.3.6, the Domains page may reject both IP addresses and normal
|
||
FQDNs in the `SIP Domain` field. The symptom is a red validation icon next to
|
||
the field and the `Add New Domain` button stays disabled.
|
||
|
||
中文说明:在 OpenSIPS-CP 9.3.6 中,Domains 页面可能错误拒绝 IP 和普通域名,表现为输入框旁边红色校验图标,添加按钮不可点。
|
||
|
||
This is not a SIP limitation. SIP domains may be IPs or FQDNs, and the Domains
|
||
tool itself says:
|
||
|
||
中文说明:这不是 SIP 协议限制,SIP domain 可以是 IP,也可以是 FQDN 域名。
|
||
|
||
```text
|
||
A SIP Domain to be considered local by OpenSIPS - can be an IP or a FQDN
|
||
```
|
||
|
||
The issue is in the browser-side form validation generator:
|
||
|
||
中文说明:问题在 CP 前端表单校验生成器。
|
||
|
||
```text
|
||
/var/www/html/opensips-cp/web/common/forms.php
|
||
```
|
||
|
||
The code uses `preg_quote()` when embedding validation regexes into JavaScript.
|
||
That escapes the regex into a literal string, so JavaScript's `RegExp()` no
|
||
longer receives the intended regex.
|
||
|
||
中文说明:代码用 `preg_quote()` 把正则转给 JavaScript,导致正则被转义成普通字符串,浏览器端校验失效。
|
||
|
||
Patch:
|
||
|
||
中文说明:下面补丁把 `preg_quote()` 改成更适合 JS 字符串的 `addslashes()`。
|
||
|
||
```bash
|
||
sudo cp -a /var/www/html/opensips-cp/web/common/forms.php \
|
||
/var/www/html/opensips-cp/web/common/forms.php.bak.regexfix.$(date +%Y%m%d%H%M%S)
|
||
|
||
sudo python3 - <<'PY'
|
||
from pathlib import Path
|
||
p = Path('/var/www/html/opensips-cp/web/common/forms.php')
|
||
s = p.read_text()
|
||
s = s.replace("preg_quote($re, '/')", "addslashes($re)")
|
||
s = s.replace("preg_quote($value['validation_regex'], '/')", "addslashes($value['validation_regex'])")
|
||
p.write_text(s)
|
||
PY
|
||
|
||
php -l /var/www/html/opensips-cp/web/common/forms.php
|
||
```
|
||
|
||
On some OpenSIPS-CP 9.3.6 installs, the Domains page can still reject input
|
||
after the common form-generator patch because the Domains template ships its
|
||
own over-escaped field regex. If both IPs and normal FQDNs still show a red
|
||
validation icon, patch the Domains form itself:
|
||
|
||
中文说明:有些安装即使修了通用表单生成器,Domains 页面自己的字段正则仍然会过度转义,需要单独修 Domains 模板。
|
||
|
||
```bash
|
||
sudo cp -a /var/www/html/opensips-cp/web/tools/system/domains/template/domains.form.php \
|
||
/var/www/html/opensips-cp/web/tools/system/domains/template/domains.form.php.bak.domain-regex.$(date +%Y%m%d%H%M%S)
|
||
|
||
sudo python3 - <<'PY'
|
||
from pathlib import Path
|
||
p = Path('/var/www/html/opensips-cp/web/tools/system/domains/template/domains.form.php')
|
||
s = p.read_text()
|
||
lines = []
|
||
for line in s.splitlines():
|
||
if '"domain", "n", $domain_form' in line:
|
||
indent = line[:len(line) - len(line.lstrip())]
|
||
lines.append(indent + '"domain", "n", $domain_form[\'domain\'], 128, null);')
|
||
else:
|
||
lines.append(line)
|
||
p.write_text('\n'.join(lines) + '\n')
|
||
PY
|
||
|
||
php -l /var/www/html/opensips-cp/web/tools/system/domains/template/domains.form.php
|
||
sudo systemctl reload apache2 || sudo systemctl restart apache2
|
||
```
|
||
|
||
This only disables the browser-side regex for the `SIP Domain` field; the field
|
||
remains required, and the database/OpenSIPS domain module still determine what
|
||
is actually usable. After patching, hard refresh the browser with `Ctrl+F5`.
|
||
|
||
中文说明:这个修复只关闭 SIP Domain 字段的浏览器端正则,字段仍是必填;真正是否可用仍由数据库和 OpenSIPS domain 模块决定。修完后浏览器要 `Ctrl+F5` 强制刷新。
|
||
|
||
The one-shot installer already applies both equivalent patches automatically.
|
||
|
||
中文说明:一键安装脚本已经自动包含这两个补丁。
|
||
|
||
For the current workstation, `100.93.185.30` was also inserted directly into the
|
||
`domain` table to unblock user creation:
|
||
|
||
中文说明:当前工作站为了先让用户创建功能可用,已经把 `100.93.185.30` 直接写入 `domain` 表。
|
||
|
||
```sql
|
||
INSERT INTO domain (domain, attrs, accept_subdomain, last_modified)
|
||
SELECT '100.93.185.30', NULL, 0, NOW()
|
||
WHERE NOT EXISTS (SELECT 1 FROM domain WHERE domain='100.93.185.30');
|
||
```
|
||
|
||
The `domain` runtime module was enabled:
|
||
|
||
中文说明:同时启用了 OpenSIPS 的 `domain.so` 模块,并使用数据库模式。
|
||
|
||
```opensips
|
||
loadmodule "domain.so"
|
||
modparam("domain", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
|
||
modparam("domain", "db_mode", 1)
|
||
```
|
||
|
||
Validation:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"domain_reload"}'
|
||
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":2,"method":"domain_dump"}'
|
||
```
|
||
|
||
Expected `domain_dump` output includes:
|
||
|
||
中文说明:期望 `domain_dump` 输出中包含当前服务器域名/IP。
|
||
|
||
```text
|
||
100.93.185.30
|
||
```
|
||
|
||
## Security notes
|
||
|
||
中文说明:安全注意事项。
|
||
|
||
- Keep MI HTTP bound to `127.0.0.1`.
|
||
- Do not expose `0.0.0.0:8888` to the network.
|
||
- Change the OpenSIPS-CP admin password.
|
||
- Use a stronger database password in production.
|
||
- Restrict SIP source IPs using `permissions` / `address` rules.
|
||
- Open RTP port range only where needed, for example `30000-40000/udp`.
|
||
|
||
## Runtime checks
|
||
|
||
中文说明:运行状态检查命令。
|
||
|
||
```bash
|
||
systemctl is-active mariadb apache2 opensips rtpengine-daemon
|
||
ss -ltnup | grep -E '(:80|:5060|:8888|:2223|:2812)'
|
||
curl -I http://127.0.0.1/cp/
|
||
curl -fsS -u admin:monit http://127.0.0.1:2812/ | grep -m1 Monit
|
||
curl -X POST http://127.0.0.1:8888/mi \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"ps"}'
|
||
```
|