# 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"}' ```