docs: align service upgrade guidance with hardened layout

This commit is contained in:
agessaman
2026-07-28 12:01:20 -07:00
parent 22f36b0484
commit fda34a839e
5 changed files with 191 additions and 37 deletions
+4 -2
View File
@@ -109,7 +109,7 @@ sudo ./install-service.sh
2. Configure the bot:
```bash
sudo nano /opt/meshcore-bot/config.ini
sudo nano /etc/meshcore-bot/config.ini
```
3. Start the service:
@@ -133,7 +133,9 @@ make deb
sudo dpkg -i dist/meshcore-bot_*.deb
```
The package installs the bot to `/opt/meshcore-bot/`, installs a systemd unit, and creates a `meshcore-bot` system user.
The package installs root-owned code in `/opt/meshcore-bot/`, configuration in
`/etc/meshcore-bot/`, mutable state in `/var/lib/meshcore-bot/`, logs in
`/var/log/meshcore-bot/`, and creates a `meshcore-bot` system user.
### Docker Deployment
For containerized deployment using Docker:
+1 -1
View File
@@ -58,7 +58,7 @@ Run the bot as a system service on Linux:
```bash
sudo ./install-service.sh
sudo nano /opt/meshcore-bot/config.ini # configure
sudo nano /etc/meshcore-bot/config.ini # configure
sudo systemctl start meshcore-bot
sudo systemctl status meshcore-bot
```
+98 -34
View File
@@ -5,10 +5,15 @@ This guide explains how to install the MeshCore Bot as a systemd service on Linu
## Prerequisites
- Linux system with systemd
- Python 3.7+ (Python 3.12+ recommended; on 3.11 the meshcore dependency has an f-string bug — the install script patches it automatically)
- Python 3.10+
- `rsync`
- Root/sudo access
- MeshCore-compatible device
You can install from a Debian package instead of the standalone script. See the
[README](https://github.com/agessaman/meshcore-bot#debian-package-deb) for build
instructions.
## Quick Installation
1. **Clone and navigate to the bot directory:**
@@ -24,7 +29,7 @@ This guide explains how to install the MeshCore Bot as a systemd service on Linu
3. **Configure the bot:**
```bash
sudo nano /opt/meshcore-bot/config.ini
sudo nano /etc/meshcore-bot/config.ini
```
4. **Start the service:**
@@ -37,40 +42,94 @@ This guide explains how to install the MeshCore Bot as a systemd service on Linu
sudo systemctl status meshcore-bot
```
## Upgrading
After updating the source checkout, run:
```bash
sudo ./install-service.sh --upgrade
```
The upgrader rebuilds the virtual environment, updates the service unit, and migrates
legacy relative paths into the current service layout. It preserves the active
configuration, database, logs, local plugins, and installed-only alternative command
files. If an upgrade fails after stopping an active service, it makes one best-effort
attempt to restart that service while preserving the original failure status.
Read the [upgrade guide](upgrade.md) before upgrading an existing installation.
## Manual Installation
If you prefer to install manually:
### 1. Create Service User
```bash
sudo useradd --system --no-create-home --shell /bin/false meshcore
```
### 2. Create Directories
```bash
sudo mkdir -p /opt/meshcore-bot
sudo mkdir -p /var/log/meshcore-bot
sudo install -d -o root -g root -m 0755 /opt/meshcore-bot
sudo install -d -o meshcore -g meshcore -m 0700 /etc/meshcore-bot
sudo install -d -o meshcore -g meshcore -m 0700 /var/lib/meshcore-bot
sudo install -d -o meshcore -g meshcore -m 0750 /var/log/meshcore-bot
```
### 3. Copy Bot Files
This manual copy sequence is for a clean installation. Use the supported upgrader
above for an existing installation so installed-only alternative commands and runtime
state are preserved.
```bash
sudo cp -r . /opt/meshcore-bot/
sudo chown -R meshcore:meshcore /opt/meshcore-bot
sudo chown -R meshcore:meshcore /var/log/meshcore-bot
sudo rsync -a --delete \
--exclude=.git --exclude=venv --exclude=.venv \
--exclude=config.ini --exclude=local/ \
./ /opt/meshcore-bot/
sudo chown -R root:root /opt/meshcore-bot
sudo chmod -R go-w /opt/meshcore-bot
```
### 4. Install Service File
Keep custom plugins under `/var/lib/meshcore-bot/local/`; do not make the executable
tree writable by the service account.
### 4. Create the Virtual Environment
```bash
sudo cp meshcore-bot.service /etc/systemd/system/
sudo python3 -m venv /opt/meshcore-bot/venv
sudo /opt/meshcore-bot/venv/bin/pip install \
-r /opt/meshcore-bot/requirements.txt
```
### 5. Install Configuration
```bash
sudo cp /opt/meshcore-bot/config.ini.example /etc/meshcore-bot/config.ini
sudo chown meshcore:meshcore /etc/meshcore-bot/config.ini
sudo chmod 0600 /etc/meshcore-bot/config.ini
```
Set these paths in the active configuration:
```ini
[Bot]
db_path = /var/lib/meshcore-bot/meshcore_bot.db
local_dir_path = /var/lib/meshcore-bot/local
[Logging]
log_file = /var/log/meshcore-bot/meshcore_bot.log
```
### 6. Install the Service File
```bash
sudo cp /opt/meshcore-bot/meshcore-bot.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable meshcore-bot
```
### 5. Install Dependencies
```bash
sudo pip3 install -r /opt/meshcore-bot/requirements.txt
```
## Service Management
### Start/Stop/Restart
@@ -105,10 +164,10 @@ sudo systemctl disable meshcore-bot # Don't start on boot
## Configuration
The bot configuration is located at `/opt/meshcore-bot/config.ini`. Edit it with:
The active bot configuration is `/etc/meshcore-bot/config.ini`. Edit it with:
```bash
sudo nano /opt/meshcore-bot/config.ini
sudo nano /etc/meshcore-bot/config.ini
```
After changing configuration, you can reload in place (no process restart):
@@ -126,9 +185,11 @@ sudo systemctl restart meshcore-bot
## Service Features
### Security
- Runs as dedicated `meshcore` user
- No shell access for service user
- Restricted file system access
- Executable code and the virtual environment are root-owned
- Only configuration, state, and log directories are service-writable
- Resource limits (512MB RAM, 50% CPU)
### Reliability
@@ -147,22 +208,21 @@ sudo systemctl restart meshcore-bot
### Service Won't Start
1. Check service status: `sudo systemctl status meshcore-bot`
2. View logs: `sudo journalctl -u meshcore-bot -n 50`
3. Check configuration: `sudo nano /opt/meshcore-bot/config.ini`
4. Verify dependencies: `sudo pip3 list | grep meshcore`
3. Check configuration: `sudo nano /etc/meshcore-bot/config.ini`
4. Verify dependencies: `/opt/meshcore-bot/venv/bin/pip list | grep meshcore`
### SyntaxError: f-string: unmatched '[' (Python 3.11)
If the bot fails on import with this error in `meshcore/commands/contact.py`, you are on Python 3.11 and the **meshcore** dependency uses an f-string that only works on Python 3.12+.
### Dependency Import or Syntax Errors
**Options:**
- **Recommended:** Use Python 3.12+ (create the venv with `python3.12` if available, then re-run `./install-service.sh --upgrade`).
- **Or:** Re-run the install script so it can patch the installed package:
`sudo ./install-service.sh --upgrade`
The script detects Python 3.11 and patches the meshcore file in the venv.
- **Manual patch:** Edit `/opt/meshcore-bot/venv/lib/python3.11/site-packages/meshcore/commands/contact.py`, find the line containing `contact["adv_name"]` inside the f-string, and change it to `contact['adv_name']` (single quotes around `adv_name`).
Do not patch installed dependencies in place. Update the source checkout and rerun
`sudo ./install-service.sh --upgrade` so the installer creates a fresh virtual
environment from the current requirements.
### Permission Issues
1. Check file ownership: `ls -la /opt/meshcore-bot/`
2. Fix permissions: `sudo chown -R meshcore:meshcore /opt/meshcore-bot`
2. Confirm code is root-owned and not writable by `meshcore`.
3. Confirm `/etc/meshcore-bot`, `/var/lib/meshcore-bot`, and
`/var/log/meshcore-bot` are owned by `meshcore`.
### Connection Issues
1. Verify device connection (serial port, BLE, etc.)
@@ -186,9 +246,12 @@ sudo ./uninstall-service.sh
This will:
- Stop and disable the service
- Remove systemd service file
- Remove installation directory
- Remove log directory
- Remove service user
- Optionally remove the installation and log directories
- Optionally remove the service user
The current uninstaller preserves `/etc/meshcore-bot` and `/var/lib/meshcore-bot`.
Back up and remove those directories separately if you want to erase all configuration
and state.
## File Locations
@@ -196,8 +259,9 @@ This will:
|-----------|----------|
| Service file | `/etc/systemd/system/meshcore-bot.service` |
| Bot files | `/opt/meshcore-bot/` |
| Configuration | `/opt/meshcore-bot/config.ini` |
| Logs | `/var/log/meshcore-bot/` (if configured) |
| Configuration | `/etc/meshcore-bot/config.ini` |
| Database and local plugins | `/var/lib/meshcore-bot/` |
| Logs | `/var/log/meshcore-bot/` |
| System logs | `journalctl -u meshcore-bot` |
## Advanced Configuration
@@ -228,5 +292,5 @@ Environment=CUSTOM_VAR=value
For issues with the service installation:
1. Check the logs: `sudo journalctl -u meshcore-bot -f`
2. Verify configuration: `sudo nano /opt/meshcore-bot/config.ini`
2. Verify configuration: `sudo nano /etc/meshcore-bot/config.ini`
3. Test manually: `sudo -u meshcore python3 /opt/meshcore-bot/meshcore_bot.py`
+68
View File
@@ -2,6 +2,74 @@
This document describes changes that may affect users upgrading from previous versions.
## Upgrading from v0.9.3 to v0.9.4
### Service Layout and Ownership
The standalone installer and Debian package now keep executable code root-owned and
separate mutable runtime data:
| Component | Linux | macOS |
|-----------|-------|-------|
| Code and virtual environment | `/opt/meshcore-bot` | `/usr/local/meshcore-bot` |
| Configuration | `/etc/meshcore-bot/config.ini` | `/usr/local/etc/meshcore-bot/config.ini` |
| Database and local plugins | `/var/lib/meshcore-bot` | `/usr/local/var/lib/meshcore-bot` |
| Logs | `/var/log/meshcore-bot` | `/usr/local/var/log/meshcore-bot` |
Run `sudo ./install-service.sh --upgrade` from an updated source checkout. The
installer requires Python 3.10+ and `rsync`. It stops an active service before the
database migration, copies relative-path databases coherently, rewrites the migrated
configuration, builds a fresh virtual environment, and restarts a service that was
active before the upgrade.
Before upgrading, keep a separate backup of your configuration and database. The
installer preserves:
- the active configuration and absolute custom paths;
- relative-path databases, logs, and the `local/` plugin tree;
- installed-only files under `modules/commands/alternatives/`.
Trusted source versions still replace shipped alternative commands. If the upgrade
fails after stopping an active service, the installer attempts one best-effort restart
and retains the original failure exit status. Inspect the reported error before
retrying.
### Configuration Compatibility
v0.9.3 shipped configuration examples pass the v0.9.4 strict validator. Normal startup
warns about unknown sections or keys without refusing to start. You can check a config
before upgrading:
```bash
python3 validate_config.py --config /path/to/config.ini --strict
```
### Outbound HTTP and Feeds
Outbound HTTP now validates every resolved address and redirect. Private feed URLs
remain disabled by default; set `allow_private_urls = true` only for intentional
private-network feeds. Cloud metadata and non-unicast destinations remain blocked.
Feed responses are bounded by `max_response_bytes` and `max_parsed_items`.
### Optional Geocoding Data
`pycountry` and `us` remain optional under the `geo` extra. Install them for improved
country and US-state normalization:
```bash
pip install -e ".[geo]"
```
The standalone installer also offers the geocoding extras interactively.
## Upgrading from v0.8 to v0.9
- Python 3.10+ is required.
- The global `[Aliases]` section was replaced by per-command `aliases =` keys.
- Database migrations run automatically at startup.
- Review web-viewer authentication before binding beyond localhost.
- Connection and radio settings still require a process restart after changes.
## Upgrading from v0.7
### Config Compatibility
+20
View File
@@ -67,6 +67,26 @@ def test_standalone_installer_separates_code_and_private_state():
assert "Previously active service was restarted after the failed upgrade" in installer
def test_service_documentation_matches_hardened_layout() -> None:
readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8")
getting_started = (REPO_ROOT / "docs/getting-started.md").read_text(encoding="utf-8")
service_docs = (REPO_ROOT / "docs/service-installation.md").read_text(
encoding="utf-8"
)
upgrade_docs = (REPO_ROOT / "docs/upgrade.md").read_text(encoding="utf-8")
for text in (readme, getting_started, service_docs):
assert "sudo nano /opt/meshcore-bot/config.ini" not in text
assert "sudo nano /etc/meshcore-bot/config.ini" in text
assert "Python 3.10+" in service_docs
assert "`rsync`" in service_docs
assert "sudo chown -R meshcore:meshcore /opt/meshcore-bot" not in service_docs
assert "patches the meshcore file" not in service_docs
assert "/var/lib/meshcore-bot" in service_docs
assert "Upgrading from v0.9.3 to v0.9.4" in upgrade_docs
def test_service_sync_preserves_only_installed_only_alternatives(tmp_path: Path) -> None:
source = tmp_path / "source"
installed = tmp_path / "installed"