---
name: server-environment-setup
title: Server Tool Setup on Restricted Linux
category: devops
description: Installing and configuring CLI tools, Python packages, and browsers on headless Linux servers with limited privileges (e.g., ZimaOS, CasaOS, NAS environments).
---

# Server Tool Setup on Restricted Linux

## Context
Self-hosted environments like ZimaOS/CasaOS often run as restricted users without system pip, without root, and with Docker sockets owned by root. This skill covers reliable workarounds for installing and running modern CLI tools, Python packages, and browser automation.

## 1. Python pip Without Root
When `pip` is missing and system paths are non-writable:

### Option A: Use ensurepip (if bundled pip wheel is present)
On minimalist systems (e.g., ZimaOS), `pip` may be absent but `ensurepip` still carries a bundled wheel:

```bash
# Check if ensurepip is available
python3 -m ensurepip --help 2>/dev/null && echo "ensurepip available"

# Install pip into user space
python3 -m ensurepip --upgrade --user

# Result: pip lands in ~/.local/bin/pip
# If ~/.local is root-owned (common on ZimaOS), override with PYTHONUSERBASE:
export PYTHONUSERBASE=/DATA/AppData/hermes/.local
python3 -m ensurepip --upgrade --user
# pip now at $PYTHONUSERBASE/bin/pip
```

### Option B: Download get-pip.py (fallback)
When `ensurepip` is also missing:

```bash
# Download get-pip.py
curl -sSL https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py

# Install into user home via PYTHONUSERBASE
PYTHONUSERBASE=/DATA/AppData/hermes/.local python3 /tmp/get-pip.py --user --no-warn-script-location

# Usage pattern
PYTHONUSERBASE=/DATA/AppData/hermes/.local /DATA/AppData/hermes/.local/bin/pip install <package>
PYTHONUSERBASE=/DATA/AppData/hermes/.local python3 -m <package>
```

**Pitfall:** If `~/.local` resolves to a root-owned path (e.g., `/DATA/.local`), override with explicit `PYTHONUSERBASE`.

## 2. Single-Binary CLI Tools
When the system package manager is unavailable, download pre-built binaries directly into a user-managed `bin/` directory:

```bash
# yt-dlp
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp \
  -o /DATA/AppData/hermes/bin/yt-dlp
chmod +x /DATA/AppData/hermes/bin/yt-dlp

# Himalaya (find latest release asset first)
curl -L <release-url> -o /DATA/AppData/hermes/bin/himalaya
chmod +x /DATA/AppData/hermes/bin/himalaya
```

**Verification:** `which <tool> && <tool> --version`

## 3. Playwright + Chromium on Headless Linux
Playwright's bundled Chromium often fails on headless servers due to missing system libraries.

**Installation:**
```bash
PYTHONUSERBASE=/DATA/AppData/hermes/.local /DATA/AppData/hermes/.local/bin/pip install playwright
PYTHONUSERBASE=/DATA/AppData/hermes/.local python3 -m playwright install chromium
```

**Required system libraries** (install via sudo if available):
```bash
sudo apt-get install -y \
  libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
  libxcomposite1 libxdamage1 libxrandr2 libgbm1 \
  libxss1 libasound2
```

**Verification:**
```bash
PYTHONUSERBASE=/DATA/AppData/hermes/.local python3 -c \
  "from playwright.sync_api import sync_playwright; p = sync_playwright().start(); print(p.chromium); p.stop()"
```

## 4. Docker Permission Issues
If the Docker socket is root-owned (`/var/run/docker.sock`), the user cannot run `docker ps` without root or `docker` group membership. Workarounds:
- Use `sudo` if explicitly granted for docker commands.
- Add user to docker group: `sudo usermod -aG docker $USER` (requires re-login).
- Alternative: Query CasaOS app status via its HTTP API instead of Docker CLI.
- If apps expose HTTP health endpoints, prefer HTTP checks over Docker inspection.

**ZimaOS/CasaOS specific:** The user account is typically *not* in the `docker` group by default. After adding with `usermod`, a new shell session is required before `docker ps` works without `sudo`. See `references/zimaos-specific.md`.

## 5. Sudoers Setup for Automation
Grant only the specific rights needed, never blanket sudo.

**Gateway restart only:**
```bash
echo 'az-a ALL=(root) NOPASSWD: /usr/bin/systemctl restart hermes-gateway, /usr/bin/systemctl stop hermes-gateway, /usr/bin/systemctl start hermes-gateway, /usr/bin/systemctl status hermes-gateway' | sudo tee /etc/sudoers.d/hermes-gateway
sudo chmod 0440 /etc/sudoers.d/hermes-gateway
sudo visudo -c
```

**Package management:**
```bash
echo 'az-a ALL=(root) NOPASSWD: /usr/bin/apt-get, /usr/bin/apt, /usr/bin/dpkg' | sudo tee /etc/sudoers.d/hermes-admin
sudo chmod 0440 /etc/sudoers.d/hermes-admin
sudo visudo -c
```

## 6. Handling Missing System Binaries
If basic commands like `mkdir`, `chmod`, or `pip` are missing from `$PATH`, check:
1. Whether the shell is a restricted environment (e.g., container without coreutils).
2. Use Python's `os.makedirs()` / `os.chmod()` as a fallback.
3. Use `python3 -c "..."` to execute file operations when bash tools are absent.

## Pitfalls
- Playwright downloads browsers to `~/.cache/ms-playwright/`, which may be root-owned on some systems. Override with `PLAYWRIGHT_BROWSERS_PATH` if needed.
- Chromium headless shell lacks video codecs; use full Chrome (`playwright install chrome`) if media playback is required.
- Always verify tool installations with `--version` or a minimal test script before assuming they work.
- `sudo` commands without `NOPASSWD` will fail in automated scripts because no TTY is present.

## Verification Checklist
After each installation:
1. `which <tool>` confirms it's on PATH.
2. `<tool> --version` confirms it executes.
3. A minimal functional test (e.g., `yt-dlp --help`, a small Playwright script) confirms runtime dependencies are satisfied.

## References
- `references/zimaos-specific.md` — CasaOS/ZimaOS quirks (Docker group, .local ownership)
- `references/google-workspace-on-restricted-headless.md` — OAuth and pip bootstrap for Google Workspace skill
- `references/google-api-stdlib-workaround.md` — Using Google REST APIs with only Python stdlib (no pip, no google-api-python-client)
