Nextcloud

Self-hosted file sync and share. No WeChat 25MB file limits. No compression destroying PDFs. Students upload assignments, teachers distribute materials.

Docker Compose

services:
  db:
    image: mariadb:10.6
    container_name: nextcloud-db
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
      - MYSQL_PASSWORD=nextcloud
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
    volumes:
      - db:/var/lib/mysql

  app:
    image: nextcloud:latest
    container_name: nextcloud-app
    ports:
      - "8080:80"
    links:
      - db
    volumes:
      - nextcloud:/var/www/html
    restart: always
    environment:
      - MYSQL_PASSWORD=nextcloud
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=db

volumes:
  db:
  nextcloud:
โš ๏ธ Default credentials Admin: admin / admin123. Change immediately after first login via the web UI at http://HER:8080.

Why not use the snap package?

The snap is easier but limits configuration. Docker gives full control over versions, backups, and migration. The data volumes live in /var/lib/docker/volumes/ and can be backed up with Restic.

Jellyfin

Media server for educational videos. Students watch on any device via browser. No internet required after setup.

Docker Compose

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    ports:
      - "8096:8096"
    volumes:
      - /home/wm/ai-stack/jellyfin/config:/config
      - /home/wm/ai-stack/jellyfin/cache:/cache
      - /home/wm/media:/media:ro
    restart: unless-stopped
    user: "1000:1000"
๐Ÿ’ก Permission fix Jellyfin runs as UID 1000. If config/cache directories are owned by root, the container fails silently. Fix: sudo chown -R 1000:1000 /home/wm/ai-stack/jellyfin/

Adding media

Place video files in /home/wm/media/ (or wherever your media mount is). Jellyfin scans automatically. Organize by folders: Movies/, TV/, Education/.

AdGuard Home

Network-wide ad and tracker blocker. Every device on the LAN benefits โ€” no per-device setup needed.

Docker Compose

services:
  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguardhome
    ports:
      - "3001:3000"    # Web UI
      # DNS ports removed โ€” systemd-resolved owns 53
    volumes:
      - /home/wm/ai-stack/adguard/work:/opt/adguardhome/work
      - /home/wm/ai-stack/adguard/conf:/opt/adguardhome/conf
    restart: unless-stopped
โš ๏ธ Port 53 conflict Ubuntu's systemd-resolved binds port 53. You cannot map AdGuard's DNS port without stopping systemd-resolved first. We mapped the web UI to port 3001 instead. To use AdGuard as DNS, configure it in your router or set DNS manually on clients to point at the machine's IP with port 53 (requires systemctl stop systemd-resolved).

Setup

  1. Open http://HER:3001
  2. Follow the wizard โ€” set admin password
  3. Add filter lists (default ones are good)
  4. Configure upstream DNS (e.g., 223.5.5.5 for AliDNS in China, or 1.1.1.1 for Cloudflare)

Kiwix

Offline Wikipedia and other ZIM files. Entire encyclopedia on disk. No internet required.

Installation

# Download tools (slow in China โ€” use --timeout=7200)
curl -L -o kiwix-tools.tar.gz \
  "https://download.kiwix.org/release/kiwix-tools/kiwix-tools_linux-x86_64-3.7.0.tar.gz"
tar -xzf kiwix-tools.tar.gz
sudo mv kiwix-tools_*/kiwix-serve /usr/local/bin/
sudo mv kiwix-tools_*/kiwix-manage /usr/local/bin/

# Download a ZIM file (Wikipedia, Wiktionary, etc.)
# From https://download.kiwix.org/zim/wikipedia/
curl -L -o wikipedia_en_all_maxi.zim \
  "https://download.kiwix.org/zim/wikipedia/wikipedia_en_all_maxi_YYYY-MM.zim"

# Create library file
kiwix-manage library.zim.xml add wikipedia_en_all_maxi.zim

# Start server
kiwix-serve --library library.zim.xml --port 8081
๐Ÿ’ก ZIM files are large English Wikipedia maxi is ~90 GB. Start with nopic (~30 GB) or mini (~5 GB) for faster download. Wiktionary is ~2 GB and extremely useful for language learners.

Quick Reference

Service URL Docker Status Check
Ollama http://HER:11434 Native (user service) curl http://localhost:11434/api/tags
Open WebUI http://HER:3000 ghcr.io/open-webui/open-webui:main Web page loads
Nextcloud http://HER:8080 nextcloud:latest curl http://localhost:8080/status.php
Jellyfin http://HER:8096 jellyfin/jellyfin:latest curl http://localhost:8096/System/Info/Public
AdGuard http://HER:3001 adguard/adguardhome:latest Web page loads
Kiwix http://HER:8081 Native binary Web page loads
๐Ÿ’ก Replace HER In all URLs above, HER means the machine's LAN IP. At school this was 10.39.26.217. At home it will be different. Use ip addr show to find the current IP.