Install native Asterisk as a verified user systemd service

This commit is contained in:
2026-10-03 05:30:56 +08:00
parent b91016511c
commit 57960c9fca
11 changed files with 142 additions and 84 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ by this project are:
- `sip-go-agent-dispatcher.service`
- `sip-go-agent-agent.service`
- the separately managed native `asterisk.service`
- the separately managed native `go-sip-asterisk.service` under `rogee`'s `systemd --user` (production requires lingering)
RabbitMQ, OSS, AI providers and SaaS are external endpoints. They are not
installed by the production package and are not started by systemd or Docker.
+15 -10
View File
@@ -12,16 +12,21 @@ The pinned source input is:
- Archive `../packages/asterisk-22.10.1-source.tar.gz`
- SHA-256 `373c98f4d4a1b923b42def0aee03f4e36aca9d1c244a8eeda646da8a97f89663`
`build-asterisk-native.sh` can reproduce a native stage from the local pinned
source/dependency archives using the Debian package list in
`debian-build-packages.lock`; `install-asterisk-native.sh` installs that stage
and the systemd unit without overwriting `/etc/asterisk`. Before production use,
the Cell owner must verify its dependencies/licence/security review, install the
management-approved static `pjsip.conf`/ARI/RTP configuration, and review/start
the systemd unit explicitly. Do not silently substitute another Asterisk version or a
container image. The Go Agent package only consumes the resulting approved static Cell artifact
and reports its applied revision. Local validation may use isolated MQ/OSS/AI
fixtures, but those are not production deployments.
`build-asterisk-native.sh` reproduces the stage from the pinned source and
local dependency cache; the build selects no downloaded core sounds/MOH.
The native package includes its `build-platform` marker and
`install-asterisk-user.sh`. Run that installer as `rogee`, never as root;
it verifies the stage hash and required libraries, installs into `~/.local/opt/`,
sets up `~/.config/go-sip-asterisk/` without overwriting existing files, and
installs `go-sip-asterisk.service` under `systemd --user`. Production requires
`loginctl enable-linger rogee` and a verified reboot-persistent `enabled+active`
service; `--nonprod` allows a session-scoped Debian 12 native build but does
not certify reboot persistence. The management-approved static `pjsip.conf`,
ARI and RTP configuration must be supplied separately. The bundled stage has
no live SIP trunk or dialing authorization; verify loaded endpoints and contacts
before any call. Do not substitute another Asterisk version or a container image.
The Go Agent package only consumes the resulting approved Cell artifact and
reports its applied revision. Local Mock fixtures do not prove real services.
Before every real outbound attempt, the operator must obtain a fresh user
confirmation in the current conversation that names the SIP channel, raw target
-22
View File
@@ -1,22 +0,0 @@
[Unit]
Description=Asterisk SIP Cell 22.10.1 (physical host)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=asterisk
Group=asterisk
WorkingDirectory=/var/lib/asterisk
ExecStart=/usr/sbin/asterisk -f -U asterisk -G asterisk -vvvg
ExecStop=/usr/sbin/asterisk -rx "core stop now"
Restart=on-failure
RestartSec=5s
UMask=0077
LimitNOFILE=65536
PrivateTmp=yes
ProtectHome=yes
ReadWritePaths=/etc/asterisk /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk
[Install]
WantedBy=multi-user.target
+10 -6
View File
@@ -11,9 +11,10 @@ OUT=${OUT_DIR:-"$PKG/asterisk-$VERSION-native"}
JOBS=${JOBS:-1}
WORK=${WORK_DIR:-"$ROOT/.local/asterisk-build-$VERSION"}
NONPROD=${NONPROD:-0}
. /etc/os-release
OS_ID=$(. /etc/os-release; printf '%s' "$ID")
OS_VERSION=$(. /etc/os-release; printf '%s' "$VERSION_ID")
source "$ROOT/deploys/cell/native-platform.sh"
require_native_platform "$ID" "$VERSION_ID" "$(uname -m)" "debian:$VERSION_ID:x86_64" "$NONPROD"
require_native_platform "$OS_ID" "$OS_VERSION" "$(uname -m)" "debian:$OS_VERSION:x86_64" "$NONPROD"
[[ -f "$SRC_ARCHIVE" && -f "$SRC_SHA" ]] || { echo 'Asterisk source archive/checksum missing' >&2; exit 1; }
[[ -d "$DEPS" ]] || { echo 'Asterisk dependency cache missing' >&2; exit 1; }
@@ -26,6 +27,10 @@ tar -xzf "$SRC_ARCHIVE" -C "$WORK"
SRC="$WORK/asterisk-$VERSION"
cd "$SRC"
EXTERNALS_CACHE_DIR="$OUT/cache" ./configure --with-pjproject-bundled --with-jansson-bundled
# Sound archives are not part of the pinned offline inputs; never fetch
# unverified downloads during an otherwise reproducible native build.
EXTERNALS_CACHE_DIR="$OUT/cache" make menuselect.makeopts
./menuselect/menuselect --disable CORE-SOUNDS-EN-GSM --disable MOH-OPSOUND-WAV menuselect.makeopts
EXTERNALS_CACHE_DIR="$OUT/cache" make -j"$JOBS"
STAGE="$WORK/stage"
rm -rf -- "$STAGE"
@@ -35,11 +40,10 @@ EXTERNALS_CACHE_DIR="$OUT/cache" make install DESTDIR="$STAGE"
# binary package.
rm -rf -- "$STAGE/etc/asterisk"
tar -C "$STAGE" -cpf "$OUT/asterisk-$VERSION-native-stage.tar" .
cp "$ROOT/deploys/cell/asterisk.service" "$OUT/asterisk.service"
cp "$ROOT/deploys/cell/install-asterisk-native.sh" "$OUT/install-asterisk-native.sh"
cp "$ROOT/deploys/cell/install-asterisk-user.sh" "$OUT/install-asterisk-user.sh"
cp "$ROOT/deploys/cell/native-platform.sh" "$OUT/native-platform.sh"
printf 'debian:%s:x86_64\n' "$VERSION_ID" > "$OUT/build-platform"
chmod 0755 "$OUT/install-asterisk-native.sh"
printf 'debian:%s:x86_64\n' "$OS_VERSION" > "$OUT/build-platform"
chmod 0755 "$OUT/install-asterisk-user.sh"
(
cd "$OUT"
sha256sum "asterisk-$VERSION-native-stage.tar" > "asterisk-$VERSION-native-stage.tar.sha256"
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
[[ ${EUID} -eq 0 ]] || { echo 'install-asterisk-native.sh must run as root' >&2; exit 1; }
START=false
NONPROD=0
for arg in "$@"; do
case "$arg" in
--start) START=true ;;
--nonprod) NONPROD=1 ;;
*) echo "unknown option: $arg" >&2; exit 2 ;;
esac
done
PACKAGE_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
cd -- "$PACKAGE_DIR"
. /etc/os-release
[[ -f native-platform.sh && -f build-platform ]] || { echo 'native build platform metadata is missing' >&2; exit 1; }
source ./native-platform.sh
require_native_platform "$ID" "$VERSION_ID" "$(uname -m)" "$(<build-platform)" "$NONPROD"
STAGE=asterisk-22.10.1-native-stage.tar
sha256sum -c "$STAGE.sha256"
[[ -f asterisk.service ]] || { echo 'asterisk.service is missing' >&2; exit 1; }
getent group asterisk >/dev/null || groupadd --system asterisk
id -u asterisk >/dev/null 2>&1 || useradd --system --home-dir /var/lib/asterisk --shell /usr/sbin/nologin --gid asterisk asterisk
# Keep management-owned /etc/asterisk configuration intact.
tar --exclude='etc/asterisk/*' -xpf "$STAGE" -C /
ldconfig
install -d -o asterisk -g asterisk -m 0750 /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk
install -o root -g root -m 0644 asterisk.service /etc/systemd/system/asterisk.service
systemctl daemon-reload
systemctl enable asterisk.service
if [[ "$START" == true ]]; then
systemctl restart asterisk.service
fi
/usr/sbin/asterisk -V
printf 'installed asterisk=22.10.1 start=%s config_preserved=true\n' "$START"
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Native, unprivileged Asterisk installation for the approved rogee user.
set -euo pipefail
nonprod=0
if [[ ${1:-} == --nonprod ]]; then nonprod=1; shift; fi
[[ $# == 1 ]] || { echo 'usage: install-asterisk-user.sh [--nonprod] <verified-native-package-dir>' >&2; exit 2; }
[[ $(id -u) != 0 ]] || { echo 'do not run the user service installer as root' >&2; exit 1; }
package=$(cd "$1" && pwd)
. /etc/os-release
source "$(dirname "$0")/native-platform.sh"
[[ -f $package/build-platform ]] || { echo 'native build platform metadata is missing' >&2; exit 1; }
require_native_platform "$ID" "$VERSION_ID" "$(uname -m)" "$(<"$package/build-platform")" "$nonprod"
archive=asterisk-22.10.1-native-stage.tar
(cd "$package" && sha256sum -c "$archive.sha256")
if [[ $nonprod == 0 && $(loginctl show-user "$(id -un)" -p Linger --value) != yes ]]; then
echo 'enable user lingering before a production user-service installation' >&2
exit 1
fi
prefix="$HOME/.local/opt/go-sip-asterisk/22.10.1"
config="$HOME/.config/go-sip-asterisk"
state="$HOME/.local/state/go-sip-asterisk"
data="$HOME/.local/share/go-sip-asterisk"
cache="$HOME/.cache/go-sip-asterisk"
unit="$HOME/.config/systemd/user/go-sip-asterisk.service"
runtime="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/go-sip-asterisk"
[[ ! -e $prefix && ! -e $unit && ! -e $config/asterisk.conf && ! -e $config/modules.conf ]] || { echo 'existing Asterisk installation or user configuration; refuse to overwrite' >&2; exit 1; }
[[ $HOME != *[[:space:]]* ]] || { echo 'home path with whitespace is unsupported by the unit' >&2; exit 1; }
mkdir -p "$(dirname "$prefix")"
staged=$(mktemp -d "$(dirname "$prefix")/.staged.XXXXXXXX")
trap 'rm -rf "$staged"' EXIT
tar -xpf "$package/$archive" -C "$staged"
[[ -x $staged/usr/sbin/asterisk ]] || { echo 'native package has no Asterisk executable' >&2; exit 1; }
if LD_LIBRARY_PATH="$staged/usr/lib" ldd "$staged/usr/sbin/asterisk" | grep -q 'not found'; then
echo 'native Asterisk runtime libraries are missing' >&2; exit 1
fi
LD_LIBRARY_PATH="$staged/usr/lib" "$staged/usr/sbin/asterisk" -V
mv "$staged" "$prefix"
trap - EXIT
mkdir -p "$config" "$state/log" "$state/spool" "$data/db" "$data/keys" "$data/agi-bin" "$cache" "$(dirname "$unit")"
cat > "$config/asterisk.conf" <<EOF
[directories]
astcachedir => $cache
astetcdir => $config
astmoddir => $prefix/usr/lib/asterisk/modules
astvarlibdir => $data
astdbdir => $data/db
astkeydir => $data/keys
astdatadir => $prefix/var/lib/asterisk
astagidir => $data/agi-bin
astspooldir => $state/spool
astrundir => $runtime
astlogdir => $state/log
EOF
printf '[modules]\nautoload=yes\n' > "$config/modules.conf"
cat > "$unit" <<EOF
[Unit]
Description=Go SIP Cell native Asterisk (user service)
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
Environment=LD_LIBRARY_PATH=$prefix/usr/lib
RuntimeDirectory=go-sip-asterisk
WorkingDirectory=$data
ExecStart=$prefix/usr/sbin/asterisk -f -C $config/asterisk.conf
ExecReload=$prefix/usr/sbin/asterisk -C $config/asterisk.conf -rx "module reload res_pjsip.so"
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now go-sip-asterisk.service
systemctl --user is-enabled go-sip-asterisk.service
sleep 2
systemctl --user is-active --quiet go-sip-asterisk.service || { echo 'Asterisk exited during startup' >&2; exit 1; }
LD_LIBRARY_PATH="$prefix/usr/lib" "$prefix/usr/sbin/asterisk" -C "$config/asterisk.conf" -rx 'core show version' | grep -q 'Asterisk 22.10.1' || { echo 'Asterisk CLI did not report the expected live version' >&2; exit 1; }
if [[ $(loginctl show-user "$(id -un)" -p Linger --value) != yes ]]; then
echo 'nonproduction only: user lingering disabled; reboot persistence NOT verified' >&2
fi
@@ -0,0 +1 @@
debian:13:x86_64
+8 -5
View File
@@ -10,8 +10,8 @@ to Debian 12. This exception does not approve production deployment or real call
Production remains a small systemd installation on Debian 13 amd64:
1. native Asterisk Cell (`asterisk.service`), owned by the approved SIP
management release;
1. native Asterisk Cell (`go-sip-asterisk.service`) under `rogee`'s `systemd --user`,
with lingering enabled and reboot-persistent `enabled+active` verified;
2. `sip-go-agent-agent.service`;
3. `sip-go-agent-dispatcher.service`.
@@ -23,9 +23,12 @@ The pinned versions are in [`versions.lock.json`](versions.lock.json). Build
a release candidate with `build-package.sh`; it writes the archive to
`dist/packages/` and is intentionally not production-approved. Production
installation requires a clean, externally approved manifest. Build/install
Asterisk separately with the scripts in [`cell/`](cell/). The Asterisk
installer preserves `/etc/asterisk`; the management-approved static Cell
configuration is installed separately.
Asterisk separately with the scripts in [`cell/`](cell/). The Asterisk user installer preserves existing files and places the Cell
configuration under `~rogee/.config/go-sip-asterisk/`; management approves and
updates `pjsip.conf` separately. Run `install-asterisk-user.sh --nonprod <native-package-dir>`
for a Debian 12 test build; without `--nonprod`, user lingering is required
before installation. Without lingering, non-production start is session-scoped
and reboot persistence must be reported as unverified.
The Go installer creates `/opt/sip-go-agent`, `/etc/sip-go-agent` and
`/var/lib/sip-go-agent`, installs the two Go units, and enables them. It does