Enhance Raspberry Pi installer and modernize systemd deployment documentation

This commit is contained in:
Tobias Gesellchen
2026-02-14 21:53:24 +01:00
parent 5da7e001b2
commit b8ab4b5723
4 changed files with 148 additions and 22 deletions
+7
View File
@@ -9,7 +9,14 @@
* [Initial Device Setup](guides/DEVICE-INITIAL-SETUP.md)
* [HTTPS Setup](guides/HTTPS-SETUP.md)
* [Deployment](guides/DEPLOYMENT.md)
* [Raspberry Pi Guide](guides/RASPBERRY-PI.md)
* [Troubleshooting](guides/TROUBLESHOOTING.md)
* [Useful Links](#useful-links)
### Useful Links
* [Cloud Shutdown Survival Guide](guides/SURVIVAL-GUIDE.md)
* [Raspberry Pi Installer](../../scripts/raspberry-pi/README.md)
* [CLI Reference](guides/CLI-REFERENCE.md)
## Technical Reference
* [API Cookbook](reference/API-COOKBOOK.md)
+33 -19
View File
@@ -13,6 +13,10 @@ This guide covers everything you need to know to deploy robust, scalable SoundTo
- [Performance Optimization](#performance-optimization)
- [Error Handling Recovery](#error-handling-recovery)
- [Deployment Strategies](#deployment-strategies)
- [Docker Deployment](#docker-deployment)
- [Kubernetes Deployment](#kubernetes-deployment)
- [Systemd Service](#systemd-service)
- [Raspberry Pi Installer](#raspberry-pi-installer)
- [Maintenance Operations](#maintenance-operations)
---
@@ -926,39 +930,49 @@ data:
device_hosts: "192.168.1.100,192.168.1.101,192.168.1.102"
```
### Systemd Service
#### Systemd Service
A standard systemd unit for manual installation. This example assumes the binary is at `/usr/local/bin/soundtouch-service` and data is stored in `/var/lib/soundtouch-service`.
```ini
# /etc/systemd/system/soundtouch.service
# /etc/systemd/system/soundtouch-service.service
[Unit]
Description=SoundTouch Control Service
After=network.target
Wants=network.target
Description=Bose SoundTouch Service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=soundtouch
Group=soundtouch
WorkingDirectory=/opt/soundtouch
ExecStart=/opt/soundtouch/bin/soundtouch-app
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
Environment=DEVICE_HOSTS=192.168.1.100,192.168.1.101
Environment=LOG_LEVEL=info
Environment=CONFIG_FILE=/opt/soundtouch/config/production.yaml
WorkingDirectory=/var/lib/soundtouch-service
ExecStart=/usr/local/bin/soundtouch-service
Environment=PORT=80
Environment=SERVER_URL=http://soundtouch.local
# Security settings
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/soundtouch/logs
# Allow binding to privileged ports (80/443) without running as root
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
Restart=on-failure
RestartSec=5
# Security hardening
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/soundtouch-service
[Install]
WantedBy=multi-user.target
```
#### Raspberry Pi Installer
For users deploying on a Raspberry Pi, we provide a specialized automated installer that handles everything from architecture detection to security hardening.
See the [Raspberry Pi Installation Guide](RASPBERRY-PI.md) for step-by-step instructions.
---
## Maintenance Operations
@@ -1071,4 +1085,4 @@ func init() {
// Set GC target percentage
if os.Getenv("GOGC") == "" {
debug.SetGCPerc
debug.SetGCPerc
+59
View File
@@ -0,0 +1,59 @@
# Raspberry Pi Installation Guide
This guide explains how to install the `soundtouch-service` as a persistent systemd service on a Raspberry Pi (tested on Raspberry Pi Zero 2W, 3, and 4).
## Automated Installer
We provide a specialized installer script located in the `scripts/raspberry-pi/` directory of the repository.
### Features
* **Automatic start on boot**: Installs a systemd unit.
* **Non-root operation**: Uses `AmbientCapabilities` to bind to ports 80/443 without root privileges.
* **Arch Detection**: Automatically selects the correct binary for `armv7`, `arm64`, or `amd64`.
* **Easy Updates**: Re-running the script updates the binary to the latest version.
### Installation Steps
1. **Download the installer**:
```bash
curl -fsSL -o install.sh https://raw.githubusercontent.com/gesellix/bose-soundtouch/main/scripts/raspberry-pi/install.sh
```
2. **Run with sudo**:
```bash
sudo bash install.sh
```
### Overriding Defaults
You can customize the installation using environment variables:
```bash
sudo \
VERSION=v0.17.0 \
HOSTNAME_FQDN=soundtouch.local \
HTTP_PORT=80 \
HTTPS_PORT=443 \
bash install.sh
```
## Management
Once installed, use standard `systemctl` commands to manage the service:
```bash
# Check status
systemctl status soundtouch-service
# Follow logs
journalctl -u soundtouch-service -f
# Restart
sudo systemctl restart soundtouch-service
```
## Configuration
Configuration is stored in `/etc/soundtouch-service/soundtouch-service.env`. Note that settings saved via the Web UI (in `settings.json`) will take precedence over these environment variables once the service is running.
For more details, see the [scripts/raspberry-pi/README.md](../../scripts/raspberry-pi/README.md) in the repository.
+49 -3
View File
@@ -120,7 +120,13 @@ ensure_user_group() {
ensure_dirs() {
log "Creating directories"
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}"
chown -R "${SERVICE_USER}:${SERVICE_GROUP}" "${DATA_DIR}"
# Optimized ownership check: only chown if not already owned by service user
if [[ "$(stat -c '%U:%G' "${DATA_DIR}")" != "${SERVICE_USER}:${SERVICE_GROUP}" ]]; then
log "Adjusting ownership of ${DATA_DIR} to ${SERVICE_USER}:${SERVICE_GROUP}"
chown -R "${SERVICE_USER}:${SERVICE_GROUP}" "${DATA_DIR}"
fi
chmod 0755 "${CONFIG_DIR}" "${DATA_DIR}"
}
@@ -136,10 +142,17 @@ download_binary() {
if command -v curl >/dev/null 2>&1; then
curl -fsSL -o "${tmp}/soundtouch-service" "${url}"
else
wget -O "${tmp}/soundtouch-service" "${url}"
wget -qO "${tmp}/soundtouch-service" "${url}"
fi
chmod +x "${tmp}/soundtouch-service"
# Backup existing binary if it exists
if [[ -f "${BIN_PATH}" ]]; then
log "Backing up existing binary to ${BIN_PATH}.old"
cp -p "${BIN_PATH}" "${BIN_PATH}.old"
fi
install -m 0755 "${tmp}/soundtouch-service" "${BIN_PATH}"
log "Installed binary to ${BIN_PATH}"
}
@@ -201,8 +214,31 @@ EOF
reload_enable_start() {
log "Reloading systemd, enabling and starting service"
systemctl daemon-reload
systemctl enable --now "${SERVICE_NAME}.service"
systemctl enable "${SERVICE_NAME}.service"
systemctl restart "${SERVICE_NAME}.service"
log "Verifying service health..."
local health_url="http://localhost:${HTTP_PORT}/health"
local max_retries=5
local count=0
local success=false
while [[ $count -lt $max_retries ]]; do
if curl -fs "$health_url" >/dev/null 2>&1; then
success=true
break
fi
echo "Waiting for service to respond at $health_url... ($((count+1))/$max_retries)"
sleep 2
count=$((count+1))
done
if [[ "$success" = true ]]; then
log "✅ Service is healthy and responding!"
else
log "⚠️ Service started but did not respond to health check at $health_url within timeout."
log "Check logs with: journalctl -u ${SERVICE_NAME}.service -n 50"
fi
}
show_status() {
@@ -212,6 +248,16 @@ show_status() {
log "Listening sockets (${HTTP_PORT}/${HTTPS_PORT})"
ss -tulpn | grep -E ":((${HTTP_PORT})|(${HTTPS_PORT}))\b" || true
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
log "Firewall check (UFW is active)"
if ! ufw status | grep -qE "${HTTP_PORT}.*ALLOW|${HTTPS_PORT}.*ALLOW"; then
log "⚠️ UFW is active but ports ${HTTP_PORT}/${HTTPS_PORT} might be blocked."
log "Run: sudo ufw allow ${HTTP_PORT}/tcp && sudo ufw allow ${HTTPS_PORT}/tcp"
else
log "✅ UFW rules for service ports appear to be in place."
fi
fi
cat <<EOF
Try from another machine: