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
+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