Contents
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:
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"
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
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
- Open
http://HER:3001 - Follow the wizard โ set admin password
- Add filter lists (default ones are good)
- Configure upstream DNS (e.g.,
223.5.5.5for AliDNS in China, or1.1.1.1for 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
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 |
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.