Phase 2: migrate calibre stack + audiobookshelf

This commit is contained in:
Maddox 2026-01-25 22:06:42 +00:00
parent d8b21df92b
commit 575e6b7e21
6 changed files with 488 additions and 0 deletions

View file

@ -91,3 +91,9 @@ ansible-playbook playbooks/deploy-<service>.yml
- `inventory/hosts.yml` - All managed hosts with IPs and connection settings
- `inventory/group_vars/all.yml` - Global variables (timezone, NAS paths, ntfy topics)
- `docs/control-server-guide.md` - Detailed operations guide
## Additional Context Paths
The following external directories are part of this project's context:
- `~/scripts/` - Utility scripts for homelab management (add-host.sh, control-menu.sh, ssh-manager.sh, sync-dyno.sh)

View file

@ -0,0 +1,25 @@
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
restart: unless-stopped
ports:
- "13378:80"
volumes:
- ./config:/config
- ./metadata:/metadata
- /mnt/nas/media/audiobooks:/audiobooks
networks:
- proxy
labels:
- "autoheal=true"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
resources:
limits:
memory: 1G
cpus: "1.0"
networks:
proxy:
external: true

View file

@ -0,0 +1,66 @@
services:
calibre-server:
image: linuxserver/calibre:latest
container_name: calibre-server
restart: unless-stopped
security_opt:
- seccomp:unconfined
ports:
- "28080:8080"
- "28081:8081"
- "28181:8181"
volumes:
- ./config:/config
- /mnt/nas/media/Books:/books
environment:
- PUID=1000
- PGID=1000
- TZ=America/Indiana/Indianapolis
- GUAC_USER=calibre
- GUAC_PASS=calibre
- CALIBRE_SERVERSIDE_BROWSE=1
networks:
- proxy
labels:
- "autoheal=true"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
resources:
limits:
memory: 1G
cpus: "1.0"
calibre-web:
image: linuxserver/calibre-web:latest
container_name: calibre-web
restart: unless-stopped
security_opt:
- seccomp:unconfined
ports:
- "28083:8083"
volumes:
- ./config:/config
- /mnt/nas/media/Books:/books:ro
environment:
- PUID=1000
- PGID=1000
- TZ=America/Indiana/Indianapolis
- DOCKER_MODS=linuxserver/mods:calibre-web-calibre
- CALIBRE_DBPATH=/books
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
networks:
- proxy
labels:
- "autoheal=true"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
depends_on:
- calibre-server
networks:
proxy:
external: true

View file

@ -0,0 +1,56 @@
---
- name: Deploy Audiobookshelf
hosts: replicant
become: true
vars:
service_dir: /home/maddox/docker/appdata/audiobookshelf
tasks:
- name: Create audiobookshelf directory
ansible.builtin.file:
path: "{{ service_dir }}"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Create config subdirectory
ansible.builtin.file:
path: "{{ service_dir }}/config"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Create metadata subdirectory
ansible.builtin.file:
path: "{{ service_dir }}/metadata"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Copy docker-compose.yml
ansible.builtin.copy:
src: ../compose-files/replicant/audiobookshelf/docker-compose.yml
dest: "{{ service_dir }}/docker-compose.yml"
owner: maddox
group: maddox
mode: "0644"
- name: Ensure proxy network exists
community.docker.docker_network:
name: proxy
state: present
- name: Deploy audiobookshelf
community.docker.docker_compose_v2:
project_src: "{{ service_dir }}"
state: present
pull: always
register: compose_result
- name: Show deployment result
ansible.builtin.debug:
msg: "Audiobookshelf deployed successfully"
when: compose_result.changed

View file

@ -0,0 +1,48 @@
---
- name: Deploy Calibre Stack (calibre-server + calibre-web)
hosts: replicant
become: true
vars:
service_dir: /home/maddox/docker/appdata/calibre
tasks:
- name: Create calibre directory
ansible.builtin.file:
path: "{{ service_dir }}"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Create config subdirectory
ansible.builtin.file:
path: "{{ service_dir }}/config"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Copy docker-compose.yml
ansible.builtin.copy:
src: ../compose-files/replicant/calibre/docker-compose.yml
dest: "{{ service_dir }}/docker-compose.yml"
owner: maddox
group: maddox
mode: "0644"
- name: Ensure proxy network exists
community.docker.docker_network:
name: proxy
state: present
- name: Deploy calibre stack
community.docker.docker_compose_v2:
project_src: "{{ service_dir }}"
state: present
pull: always
register: compose_result
- name: Show deployment result
ansible.builtin.debug:
msg: "Calibre stack deployed successfully"
when: compose_result.changed

287
scripts/migrate-phase2-books.sh Executable file
View file

@ -0,0 +1,287 @@
#!/bin/bash
# Phase 2 Migration: Calibre Stack + Audiobookshelf
# Target: replicant (.80)
# Run from control server (CT 127)
set -e
REPO_DIR="$HOME/clustered-fucks"
COMPOSE_DIR="$REPO_DIR/compose-files/replicant"
PLAYBOOK_DIR="$REPO_DIR/playbooks"
echo "=== Phase 2: Calibre Stack + Audiobookshelf Migration ==="
echo ""
# Create directories
mkdir -p "$COMPOSE_DIR/calibre"
mkdir -p "$COMPOSE_DIR/audiobookshelf"
# =============================================================================
# Calibre Stack (calibre-server + calibre-web)
# =============================================================================
cat > "$COMPOSE_DIR/calibre/docker-compose.yml" << 'EOF'
services:
calibre-server:
image: linuxserver/calibre:latest
container_name: calibre-server
restart: unless-stopped
security_opt:
- seccomp:unconfined
ports:
- "28080:8080"
- "28081:8081"
- "28181:8181"
volumes:
- ./config:/config
- /mnt/nas/media/Books:/books
environment:
- PUID=1000
- PGID=1000
- TZ=America/Indiana/Indianapolis
- GUAC_USER=calibre
- GUAC_PASS=calibre
- CALIBRE_SERVERSIDE_BROWSE=1
networks:
- proxy
labels:
- "autoheal=true"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
resources:
limits:
memory: 1G
cpus: "1.0"
calibre-web:
image: linuxserver/calibre-web:latest
container_name: calibre-web
restart: unless-stopped
security_opt:
- seccomp:unconfined
ports:
- "28083:8083"
volumes:
- ./config:/config
- /mnt/nas/media/Books:/books:ro
environment:
- PUID=1000
- PGID=1000
- TZ=America/Indiana/Indianapolis
- DOCKER_MODS=linuxserver/mods:calibre-web-calibre
- CALIBRE_DBPATH=/books
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
networks:
- proxy
labels:
- "autoheal=true"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
depends_on:
- calibre-server
networks:
proxy:
external: true
EOF
echo "[OK] Created $COMPOSE_DIR/calibre/docker-compose.yml"
# =============================================================================
# Audiobookshelf
# =============================================================================
cat > "$COMPOSE_DIR/audiobookshelf/docker-compose.yml" << 'EOF'
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
restart: unless-stopped
ports:
- "13378:80"
volumes:
- ./config:/config
- ./metadata:/metadata
- /mnt/nas/media/audiobooks:/audiobooks
networks:
- proxy
labels:
- "autoheal=true"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
resources:
limits:
memory: 1G
cpus: "1.0"
networks:
proxy:
external: true
EOF
echo "[OK] Created $COMPOSE_DIR/audiobookshelf/docker-compose.yml"
# =============================================================================
# Ansible Playbook: deploy-calibre.yml
# =============================================================================
cat > "$PLAYBOOK_DIR/deploy-calibre.yml" << 'EOF'
---
- name: Deploy Calibre Stack (calibre-server + calibre-web)
hosts: replicant
become: true
vars:
service_dir: /home/maddox/docker/appdata/calibre
tasks:
- name: Create calibre directory
ansible.builtin.file:
path: "{{ service_dir }}"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Create config subdirectory
ansible.builtin.file:
path: "{{ service_dir }}/config"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Copy docker-compose.yml
ansible.builtin.copy:
src: ../compose-files/replicant/calibre/docker-compose.yml
dest: "{{ service_dir }}/docker-compose.yml"
owner: maddox
group: maddox
mode: "0644"
- name: Ensure proxy network exists
community.docker.docker_network:
name: proxy
state: present
- name: Deploy calibre stack
community.docker.docker_compose_v2:
project_src: "{{ service_dir }}"
state: present
pull: always
register: compose_result
- name: Show deployment result
ansible.builtin.debug:
msg: "Calibre stack deployed successfully"
when: compose_result.changed
EOF
echo "[OK] Created $PLAYBOOK_DIR/deploy-calibre.yml"
# =============================================================================
# Ansible Playbook: deploy-audiobookshelf.yml
# =============================================================================
cat > "$PLAYBOOK_DIR/deploy-audiobookshelf.yml" << 'EOF'
---
- name: Deploy Audiobookshelf
hosts: replicant
become: true
vars:
service_dir: /home/maddox/docker/appdata/audiobookshelf
tasks:
- name: Create audiobookshelf directory
ansible.builtin.file:
path: "{{ service_dir }}"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Create config subdirectory
ansible.builtin.file:
path: "{{ service_dir }}/config"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Create metadata subdirectory
ansible.builtin.file:
path: "{{ service_dir }}/metadata"
state: directory
owner: maddox
group: maddox
mode: "0755"
- name: Copy docker-compose.yml
ansible.builtin.copy:
src: ../compose-files/replicant/audiobookshelf/docker-compose.yml
dest: "{{ service_dir }}/docker-compose.yml"
owner: maddox
group: maddox
mode: "0644"
- name: Ensure proxy network exists
community.docker.docker_network:
name: proxy
state: present
- name: Deploy audiobookshelf
community.docker.docker_compose_v2:
project_src: "{{ service_dir }}"
state: present
pull: always
register: compose_result
- name: Show deployment result
ansible.builtin.debug:
msg: "Audiobookshelf deployed successfully"
when: compose_result.changed
EOF
echo "[OK] Created $PLAYBOOK_DIR/deploy-audiobookshelf.yml"
# =============================================================================
# Summary
# =============================================================================
echo ""
echo "=== Files Created ==="
echo " Compose files:"
echo " - $COMPOSE_DIR/calibre/docker-compose.yml"
echo " - $COMPOSE_DIR/audiobookshelf/docker-compose.yml"
echo " Playbooks:"
echo " - $PLAYBOOK_DIR/deploy-calibre.yml"
echo " - $PLAYBOOK_DIR/deploy-audiobookshelf.yml"
echo ""
echo "=== Migration Steps ==="
echo ""
echo "1. Stop containers on alien:"
echo " ssh alien 'docker stop calibre-server calibre-web audiobookshelf'"
echo ""
echo "2. Rsync data FROM replicant (SSH into replicant first):"
echo " ssh replicant"
echo " rsync -avP maddox@192.168.1.252:/home/maddox/docker/appdata/calibre/ /home/maddox/docker/appdata/calibre/"
echo " rsync -avP maddox@192.168.1.252:/home/maddox/docker/appdata/audiobookshelf/ /home/maddox/docker/appdata/audiobookshelf/"
echo ""
echo "3. Deploy services:"
echo " cd ~/clustered-fucks"
echo " ansible-playbook playbooks/deploy-calibre.yml"
echo " ansible-playbook playbooks/deploy-audiobookshelf.yml"
echo ""
echo "4. Verify services:"
echo " curl -s -o /dev/null -w '%{http_code}' http://192.168.1.80:28080/ # calibre desktop"
echo " curl -s -o /dev/null -w '%{http_code}' http://192.168.1.80:28083/ # calibre-web"
echo " curl -s -o /dev/null -w '%{http_code}' http://192.168.1.80:13378/ # audiobookshelf"
echo ""
echo "5. Update Traefik backends to point to 192.168.1.80"
echo ""
echo "6. Cleanup alien (after verification):"
echo " ssh alien 'docker rm calibre-server calibre-web audiobookshelf'"
echo ""
echo "7. Commit changes:"
echo " git add -A && git commit -m 'Phase 2: migrate calibre stack + audiobookshelf' && git push"
echo ""
echo "=== IMPORTANT ==="
echo "Change GUAC_PASS in calibre compose before deploying!"