Add additional Docker apps and Kopia container backup
New Docker applications:
- Jellyfin (free media server with hardware acceleration)
- Frigate NVR (AI-powered object detection)
- Caddy (reverse proxy with automatic HTTPS)
- ddclient (dynamic DNS updater)
- ntfy (self-hosted push notifications)
- Uptime Kuma (service uptime monitoring)
- wg-easy (WireGuard VPN with web UI)
- Traccar (GPS tracking server)
- Portainer (Docker management UI)
Container backup system:
- Kopia backup for all Docker container data
- Backup script for configs, databases, app state
- Restore script for disaster recovery
- Backs up Immich memories, Emby metadata, Minecraft worlds, etc.
All apps use docker-compose in ~/docker/{appname}/ with storage on
primary drive where appropriate.
This commit is contained in:
@@ -91,6 +91,18 @@ Install containerized applications to `~/docker/{appname}/`:
|
|||||||
- **Mealie** - Recipe manager & meal planner
|
- **Mealie** - Recipe manager & meal planner
|
||||||
- **Minecraft Server** - Fabric server with configurable RAM limit
|
- **Minecraft Server** - Fabric server with configurable RAM limit
|
||||||
- **linux-to-sync** - Private repository setup
|
- **linux-to-sync** - Private repository setup
|
||||||
|
- **Jellyfin** - Free media server (alternative to Emby)
|
||||||
|
- **Frigate** - NVR with AI object detection
|
||||||
|
- **Caddy** - Reverse proxy with automatic HTTPS
|
||||||
|
- **ddclient** - Dynamic DNS updater
|
||||||
|
- **ntfy** - Self-hosted push notifications
|
||||||
|
- **Uptime Kuma** - Service uptime monitoring
|
||||||
|
- **wg-easy** - WireGuard VPN with web UI
|
||||||
|
- **Traccar** - GPS tracking server
|
||||||
|
- **Portainer** - Docker management UI
|
||||||
|
|
||||||
|
### Container Backup & Restore (Kopia)
|
||||||
|
Backup all Docker container data (configs, databases, app data) to your backup drives for disaster recovery. Includes restore functionality to recover containers after OS drive failure.
|
||||||
|
|
||||||
### Backup System (Optional)
|
### Backup System (Optional)
|
||||||
|
|
||||||
@@ -549,12 +561,44 @@ docker compose up -d
|
|||||||
| Immich | 2283 | http://localhost:2283 |
|
| Immich | 2283 | http://localhost:2283 |
|
||||||
| Audiobookshelf | 13378 | http://localhost:13378 |
|
| Audiobookshelf | 13378 | http://localhost:13378 |
|
||||||
| Emby | 8096 | http://localhost:8096 |
|
| Emby | 8096 | http://localhost:8096 |
|
||||||
|
| Jellyfin | 8097 | http://localhost:8097 |
|
||||||
| A.R.M. | 8080 | http://localhost:8080 |
|
| A.R.M. | 8080 | http://localhost:8080 |
|
||||||
| Filebrowser | 8085 | http://localhost:8085 |
|
| Filebrowser | 8085 | http://localhost:8085 |
|
||||||
| Magic Mirror | 8081-8083 | http://localhost:808X |
|
| Magic Mirror | 8081-8083 | http://localhost:808X |
|
||||||
| Lyrion (LMS) | 9000 | http://localhost:9000 |
|
| Lyrion (LMS) | 9000 | http://localhost:9000 |
|
||||||
| Mealie | 9925 | http://localhost:9925 |
|
| Mealie | 9925 | http://localhost:9925 |
|
||||||
| Minecraft | 25565 | localhost:25565 |
|
| Minecraft | 25565 | localhost:25565 |
|
||||||
|
| Frigate | 5000 | http://localhost:5000 |
|
||||||
|
| Caddy | 80, 443 | http://localhost |
|
||||||
|
| ntfy | 8090 | http://localhost:8090 |
|
||||||
|
| Uptime Kuma | 3001 | http://localhost:3001 |
|
||||||
|
| wg-easy | 51821 | http://localhost:51821 |
|
||||||
|
| Traccar | 8082 | http://localhost:8082 |
|
||||||
|
| Portainer | 9443 | https://localhost:9443 |
|
||||||
|
|
||||||
|
### Container Backup & Restore (Kopia)
|
||||||
|
|
||||||
|
Backup all Docker container data to your backup drives for disaster recovery.
|
||||||
|
|
||||||
|
**Run Container Backup:**
|
||||||
|
```bash
|
||||||
|
~/docker/kopia/backup-containers.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Restore Containers (after OS drive failure):**
|
||||||
|
```bash
|
||||||
|
~/docker/kopia/restore-containers.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**What Gets Backed Up:**
|
||||||
|
- All container configs and databases
|
||||||
|
- Immich facial recognition data and memories
|
||||||
|
- Emby/Jellyfin metadata and watch history
|
||||||
|
- Minecraft worlds, mods, and permissions
|
||||||
|
- Mealie recipes, Audiobookshelf progress
|
||||||
|
- All application state and settings
|
||||||
|
|
||||||
|
**Kopia Repository Location:** Your backup drive(s) in `~/drives/backupX/container-backups/`
|
||||||
|
|
||||||
### Private Repository (linux-to-sync)
|
### Private Repository (linux-to-sync)
|
||||||
|
|
||||||
@@ -900,6 +944,18 @@ This script is provided as-is for Ubuntu 24.04 Desktop installations.
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
- **v2.5**: Additional Docker apps and container backup
|
||||||
|
- Added Jellyfin (free media server with hardware acceleration)
|
||||||
|
- Added Frigate NVR (AI-powered object detection)
|
||||||
|
- Added Caddy (reverse proxy with automatic HTTPS)
|
||||||
|
- Added ddclient (dynamic DNS updater)
|
||||||
|
- Added ntfy (self-hosted push notifications)
|
||||||
|
- Added Uptime Kuma (service monitoring)
|
||||||
|
- Added wg-easy (WireGuard with web UI)
|
||||||
|
- Added Traccar (GPS tracking server)
|
||||||
|
- Added Portainer (Docker management UI)
|
||||||
|
- Added Kopia backup for all Docker containers
|
||||||
|
- Added container import/restore for disaster recovery
|
||||||
- **v2.4**: Self-hosted Docker applications
|
- **v2.4**: Self-hosted Docker applications
|
||||||
- Added Immich (photo/video backup)
|
- Added Immich (photo/video backup)
|
||||||
- Added Audiobookshelf (audiobook server)
|
- Added Audiobookshelf (audiobook server)
|
||||||
|
|||||||
@@ -1795,6 +1795,833 @@ MC_ENV
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---- JELLYFIN (Alternative to Emby) ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ JELLYFIN - Free media server (alternative to Emby) │"
|
||||||
|
echo "│ Stream movies, TV, music. No premium features locked. │"
|
||||||
|
echo "│ Port: 8096 │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Jellyfin? (y/n):" "n" INSTALL_JELLYFIN
|
||||||
|
|
||||||
|
if [ "$INSTALL_JELLYFIN" = "y" ] || [ "$INSTALL_JELLYFIN" = "Y" ]; then
|
||||||
|
echo "Installing Jellyfin..."
|
||||||
|
JELLYFIN_DIR="$DOCKER_DIR/jellyfin"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $JELLYFIN_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$JELLYFIN_DIR"
|
||||||
|
cd "$JELLYFIN_DIR"
|
||||||
|
|
||||||
|
prompt_text "Path to media folder [default: $ACTUAL_HOME/drives/primary/media]:" "$ACTUAL_HOME/drives/primary/media" MEDIA_PATH
|
||||||
|
|
||||||
|
# Get render group ID for hardware acceleration
|
||||||
|
RENDER_GID=$(getent group render | cut -d: -f3 2>/dev/null || echo "989")
|
||||||
|
|
||||||
|
cat > docker-compose.yml << JELLYFIN_COMPOSE
|
||||||
|
name: jellyfin
|
||||||
|
|
||||||
|
services:
|
||||||
|
jellyfin:
|
||||||
|
image: jellyfin/jellyfin:latest
|
||||||
|
container_name: jellyfin
|
||||||
|
hostname: jellyfin
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- TZ=$(cat /etc/timezone 2>/dev/null || echo "UTC")
|
||||||
|
devices:
|
||||||
|
- /dev/dri/renderD128:/dev/dri/renderD128
|
||||||
|
group_add:
|
||||||
|
- "$RENDER_GID"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- ./cache:/cache
|
||||||
|
- \${MEDIA_PATH}:/media:ro
|
||||||
|
ports:
|
||||||
|
- "8096:8096"
|
||||||
|
- "1900:1900/udp"
|
||||||
|
- "7359:7359/udp"
|
||||||
|
JELLYFIN_COMPOSE
|
||||||
|
|
||||||
|
cat > .env << JELLYFIN_ENV
|
||||||
|
MEDIA_PATH=$MEDIA_PATH
|
||||||
|
JELLYFIN_ENV
|
||||||
|
|
||||||
|
mkdir -p config cache
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$JELLYFIN_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Jellyfin configured at $JELLYFIN_DIR"
|
||||||
|
echo " Start with: cd $JELLYFIN_DIR && docker compose up -d"
|
||||||
|
echo " Access at: http://localhost:8096"
|
||||||
|
echo " Note: Hardware acceleration enabled (Intel GPU)"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- FRIGATE NVR ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ FRIGATE - AI-powered NVR for security cameras │"
|
||||||
|
echo "│ Object detection, recordings, 24/7 monitoring. │"
|
||||||
|
echo "│ Port: 5000 (web), 8554 (RTSP), 8555 (WebRTC) │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Frigate? (y/n):" "n" INSTALL_FRIGATE
|
||||||
|
|
||||||
|
if [ "$INSTALL_FRIGATE" = "y" ] || [ "$INSTALL_FRIGATE" = "Y" ]; then
|
||||||
|
echo "Installing Frigate..."
|
||||||
|
FRIGATE_DIR="$DOCKER_DIR/frigate"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $FRIGATE_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$FRIGATE_DIR"
|
||||||
|
cd "$FRIGATE_DIR"
|
||||||
|
|
||||||
|
prompt_text "Path for recordings [default: $ACTUAL_HOME/drives/primary/frigate]:" "$ACTUAL_HOME/drives/primary/frigate" FRIGATE_PATH
|
||||||
|
|
||||||
|
cat > docker-compose.yml << FRIGATE_COMPOSE
|
||||||
|
name: frigate
|
||||||
|
|
||||||
|
services:
|
||||||
|
frigate:
|
||||||
|
image: ghcr.io/blakeblackshear/frigate:stable
|
||||||
|
container_name: frigate
|
||||||
|
hostname: frigate
|
||||||
|
restart: unless-stopped
|
||||||
|
privileged: true
|
||||||
|
shm_size: "256mb"
|
||||||
|
environment:
|
||||||
|
- TZ=$(cat /etc/timezone 2>/dev/null || echo "UTC")
|
||||||
|
devices:
|
||||||
|
- /dev/dri/renderD128:/dev/dri/renderD128
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- \${FRIGATE_MEDIA}:/media/frigate
|
||||||
|
- type: tmpfs
|
||||||
|
target: /tmp/cache
|
||||||
|
tmpfs:
|
||||||
|
size: 1000000000
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
- "8554:8554"
|
||||||
|
- "8555:8555/tcp"
|
||||||
|
- "8555:8555/udp"
|
||||||
|
FRIGATE_COMPOSE
|
||||||
|
|
||||||
|
cat > .env << FRIGATE_ENV
|
||||||
|
FRIGATE_MEDIA=$FRIGATE_PATH
|
||||||
|
FRIGATE_ENV
|
||||||
|
|
||||||
|
mkdir -p config
|
||||||
|
mkdir -p "$FRIGATE_PATH"
|
||||||
|
|
||||||
|
# Create basic config.yml
|
||||||
|
cat > config/config.yml << 'FRIGATE_CONFIG'
|
||||||
|
mqtt:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
cameras:
|
||||||
|
# Example camera - edit with your camera details
|
||||||
|
# front_door:
|
||||||
|
# ffmpeg:
|
||||||
|
# inputs:
|
||||||
|
# - path: rtsp://user:pass@camera-ip:554/stream
|
||||||
|
# roles:
|
||||||
|
# - detect
|
||||||
|
# - record
|
||||||
|
# detect:
|
||||||
|
# width: 1280
|
||||||
|
# height: 720
|
||||||
|
# fps: 5
|
||||||
|
|
||||||
|
detectors:
|
||||||
|
default:
|
||||||
|
type: cpu
|
||||||
|
|
||||||
|
record:
|
||||||
|
enabled: true
|
||||||
|
retain:
|
||||||
|
days: 7
|
||||||
|
mode: motion
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
enabled: true
|
||||||
|
retain:
|
||||||
|
default: 7
|
||||||
|
FRIGATE_CONFIG
|
||||||
|
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$FRIGATE_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Frigate configured at $FRIGATE_DIR"
|
||||||
|
echo " Start with: cd $FRIGATE_DIR && docker compose up -d"
|
||||||
|
echo " Access at: http://localhost:5000"
|
||||||
|
echo " IMPORTANT: Edit config/config.yml to add your cameras!"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- CADDY REVERSE PROXY ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ CADDY - Automatic HTTPS reverse proxy │"
|
||||||
|
echo "│ Route domains to containers with automatic SSL certificates. │"
|
||||||
|
echo "│ Ports: 80, 443 │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Caddy reverse proxy? (y/n):" "n" INSTALL_CADDY
|
||||||
|
|
||||||
|
if [ "$INSTALL_CADDY" = "y" ] || [ "$INSTALL_CADDY" = "Y" ]; then
|
||||||
|
echo "Installing Caddy..."
|
||||||
|
CADDY_DIR="$DOCKER_DIR/caddy"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $CADDY_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$CADDY_DIR"
|
||||||
|
cd "$CADDY_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'CADDY_COMPOSE'
|
||||||
|
name: caddy
|
||||||
|
|
||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
container_name: caddy
|
||||||
|
hostname: caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- ./config:/config
|
||||||
|
- ./data:/data
|
||||||
|
- ./site:/srv
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
name: caddy_net
|
||||||
|
external: true
|
||||||
|
CADDY_COMPOSE
|
||||||
|
|
||||||
|
# Create Docker network for Caddy
|
||||||
|
docker network create caddy_net 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create example Caddyfile
|
||||||
|
cat > Caddyfile << 'CADDY_FILE'
|
||||||
|
# Caddy reverse proxy configuration
|
||||||
|
# Replace example.com with your domain
|
||||||
|
|
||||||
|
# Example: Reverse proxy to Immich
|
||||||
|
# immich.example.com {
|
||||||
|
# reverse_proxy immich_server:2283
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Example: Reverse proxy to Jellyfin
|
||||||
|
# jellyfin.example.com {
|
||||||
|
# reverse_proxy jellyfin:8096
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Example: Simple file server
|
||||||
|
# files.example.com {
|
||||||
|
# root * /srv
|
||||||
|
# file_server browse
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Localhost catch-all (for testing)
|
||||||
|
:80 {
|
||||||
|
respond "Caddy is running! Edit Caddyfile to add your sites."
|
||||||
|
}
|
||||||
|
CADDY_FILE
|
||||||
|
|
||||||
|
mkdir -p config data site
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$CADDY_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Caddy configured at $CADDY_DIR"
|
||||||
|
echo " Start with: cd $CADDY_DIR && docker compose up -d"
|
||||||
|
echo " Edit Caddyfile to add your reverse proxy rules"
|
||||||
|
echo " Created 'caddy_net' Docker network for container routing"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- DDCLIENT DYNAMIC DNS ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ DDCLIENT - Dynamic DNS updater │"
|
||||||
|
echo "│ Keep your domain pointing to your home IP. │"
|
||||||
|
echo "│ Supports: Cloudflare, DuckDNS, No-IP, and more. │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install ddclient? (y/n):" "n" INSTALL_DDCLIENT
|
||||||
|
|
||||||
|
if [ "$INSTALL_DDCLIENT" = "y" ] || [ "$INSTALL_DDCLIENT" = "Y" ]; then
|
||||||
|
echo "Installing ddclient..."
|
||||||
|
DDCLIENT_DIR="$DOCKER_DIR/ddclient"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $DDCLIENT_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$DDCLIENT_DIR"
|
||||||
|
cd "$DDCLIENT_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'DDCLIENT_COMPOSE'
|
||||||
|
name: ddclient
|
||||||
|
|
||||||
|
services:
|
||||||
|
ddclient:
|
||||||
|
image: lscr.io/linuxserver/ddclient:latest
|
||||||
|
container_name: ddclient
|
||||||
|
hostname: ddclient
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=${TZ}
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
DDCLIENT_COMPOSE
|
||||||
|
|
||||||
|
cat > .env << DDCLIENT_ENV
|
||||||
|
TZ=$(cat /etc/timezone 2>/dev/null || echo "UTC")
|
||||||
|
DDCLIENT_ENV
|
||||||
|
|
||||||
|
mkdir -p config
|
||||||
|
|
||||||
|
# Create example ddclient.conf
|
||||||
|
cat > config/ddclient.conf << 'DDCLIENT_CONF'
|
||||||
|
# ddclient configuration
|
||||||
|
# Uncomment and edit the section for your DNS provider
|
||||||
|
|
||||||
|
daemon=300
|
||||||
|
syslog=yes
|
||||||
|
pid=/var/run/ddclient/ddclient.pid
|
||||||
|
ssl=yes
|
||||||
|
|
||||||
|
# Example: Cloudflare
|
||||||
|
# use=web, web=cloudflare
|
||||||
|
# protocol=cloudflare
|
||||||
|
# zone=example.com
|
||||||
|
# login=token
|
||||||
|
# password=your-api-token
|
||||||
|
# example.com
|
||||||
|
|
||||||
|
# Example: DuckDNS
|
||||||
|
# use=web
|
||||||
|
# protocol=duckdns
|
||||||
|
# password=your-duckdns-token
|
||||||
|
# yourdomain.duckdns.org
|
||||||
|
DDCLIENT_CONF
|
||||||
|
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$DDCLIENT_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ ddclient configured at $DDCLIENT_DIR"
|
||||||
|
echo " IMPORTANT: Edit config/ddclient.conf with your DNS provider settings!"
|
||||||
|
echo " Start with: cd $DDCLIENT_DIR && docker compose up -d"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- NTFY NOTIFICATIONS ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ NTFY - Push notifications server │"
|
||||||
|
echo "│ Send notifications from scripts to your phone. │"
|
||||||
|
echo "│ Port: 8090 │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install ntfy? (y/n):" "n" INSTALL_NTFY
|
||||||
|
|
||||||
|
if [ "$INSTALL_NTFY" = "y" ] || [ "$INSTALL_NTFY" = "Y" ]; then
|
||||||
|
echo "Installing ntfy..."
|
||||||
|
NTFY_DIR="$DOCKER_DIR/ntfy"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $NTFY_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$NTFY_DIR"
|
||||||
|
cd "$NTFY_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'NTFY_COMPOSE'
|
||||||
|
name: ntfy
|
||||||
|
|
||||||
|
services:
|
||||||
|
ntfy:
|
||||||
|
image: binwiederhier/ntfy:latest
|
||||||
|
container_name: ntfy
|
||||||
|
hostname: ntfy
|
||||||
|
restart: unless-stopped
|
||||||
|
command: serve
|
||||||
|
environment:
|
||||||
|
- TZ=${TZ}
|
||||||
|
volumes:
|
||||||
|
- ./cache:/var/cache/ntfy
|
||||||
|
- ./config:/etc/ntfy
|
||||||
|
ports:
|
||||||
|
- "8090:80"
|
||||||
|
NTFY_COMPOSE
|
||||||
|
|
||||||
|
cat > .env << NTFY_ENV
|
||||||
|
TZ=$(cat /etc/timezone 2>/dev/null || echo "UTC")
|
||||||
|
NTFY_ENV
|
||||||
|
|
||||||
|
mkdir -p cache config
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$NTFY_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ ntfy configured at $NTFY_DIR"
|
||||||
|
echo " Start with: cd $NTFY_DIR && docker compose up -d"
|
||||||
|
echo " Access at: http://localhost:8090"
|
||||||
|
echo ""
|
||||||
|
echo " Send notification: curl -d \"Hello!\" localhost:8090/mytopic"
|
||||||
|
echo " Subscribe on phone: ntfy app → Add subscription → localhost:8090/mytopic"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- UPTIME KUMA ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ UPTIME KUMA - Service monitoring dashboard │"
|
||||||
|
echo "│ Monitor websites, servers, Docker containers. │"
|
||||||
|
echo "│ Port: 3001 │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Uptime Kuma? (y/n):" "n" INSTALL_UPTIMEKUMA
|
||||||
|
|
||||||
|
if [ "$INSTALL_UPTIMEKUMA" = "y" ] || [ "$INSTALL_UPTIMEKUMA" = "Y" ]; then
|
||||||
|
echo "Installing Uptime Kuma..."
|
||||||
|
UPTIME_DIR="$DOCKER_DIR/uptime-kuma"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $UPTIME_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$UPTIME_DIR"
|
||||||
|
cd "$UPTIME_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'UPTIME_COMPOSE'
|
||||||
|
name: uptime-kuma
|
||||||
|
|
||||||
|
services:
|
||||||
|
uptime-kuma:
|
||||||
|
image: louislam/uptime-kuma:1
|
||||||
|
container_name: uptime-kuma
|
||||||
|
hostname: uptime-kuma
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
UPTIME_COMPOSE
|
||||||
|
|
||||||
|
mkdir -p data
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$UPTIME_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Uptime Kuma configured at $UPTIME_DIR"
|
||||||
|
echo " Start with: cd $UPTIME_DIR && docker compose up -d"
|
||||||
|
echo " Access at: http://localhost:3001"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- WG-EASY (WireGuard with Web UI) ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ WG-EASY - WireGuard VPN with web management │"
|
||||||
|
echo "│ Easy WireGuard setup with QR codes for clients. │"
|
||||||
|
echo "│ Port: 51821 (web), 51820 (VPN) │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install wg-easy? (y/n):" "n" INSTALL_WGEASY
|
||||||
|
|
||||||
|
if [ "$INSTALL_WGEASY" = "y" ] || [ "$INSTALL_WGEASY" = "Y" ]; then
|
||||||
|
echo "Installing wg-easy..."
|
||||||
|
WGEASY_DIR="$DOCKER_DIR/wg-easy"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $WGEASY_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$WGEASY_DIR"
|
||||||
|
cd "$WGEASY_DIR"
|
||||||
|
|
||||||
|
# Get public IP or hostname
|
||||||
|
PUBLIC_IP=$(curl -s ifconfig.me 2>/dev/null || echo "your-public-ip")
|
||||||
|
WG_PASSWORD=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c 16)
|
||||||
|
|
||||||
|
prompt_text "Public IP or hostname for VPN [default: $PUBLIC_IP]:" "$PUBLIC_IP" WG_HOST
|
||||||
|
|
||||||
|
cat > docker-compose.yml << WGEASY_COMPOSE
|
||||||
|
name: wg-easy
|
||||||
|
|
||||||
|
services:
|
||||||
|
wg-easy:
|
||||||
|
image: ghcr.io/wg-easy/wg-easy:latest
|
||||||
|
container_name: wg-easy
|
||||||
|
hostname: wg-easy
|
||||||
|
restart: unless-stopped
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_MODULE
|
||||||
|
sysctls:
|
||||||
|
- net.ipv4.ip_forward=1
|
||||||
|
- net.ipv4.conf.all.src_valid_mark=1
|
||||||
|
environment:
|
||||||
|
- WG_HOST=\${WG_HOST}
|
||||||
|
- PASSWORD=\${WG_PASSWORD}
|
||||||
|
- WG_DEFAULT_DNS=1.1.1.1
|
||||||
|
volumes:
|
||||||
|
- ./config:/etc/wireguard
|
||||||
|
ports:
|
||||||
|
- "51820:51820/udp"
|
||||||
|
- "51821:51821/tcp"
|
||||||
|
WGEASY_COMPOSE
|
||||||
|
|
||||||
|
cat > .env << WGEASY_ENV
|
||||||
|
WG_HOST=$WG_HOST
|
||||||
|
WG_PASSWORD=$WG_PASSWORD
|
||||||
|
WGEASY_ENV
|
||||||
|
|
||||||
|
mkdir -p config
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$WGEASY_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ wg-easy configured at $WGEASY_DIR"
|
||||||
|
echo " Start with: cd $WGEASY_DIR && docker compose up -d"
|
||||||
|
echo " Web UI: http://localhost:51821"
|
||||||
|
echo " Password: $WG_PASSWORD (saved in .env)"
|
||||||
|
echo " VPN Port: 51820/udp (forward this in your router)"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- TRACCAR GPS TRACKING ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ TRACCAR - GPS tracking server │"
|
||||||
|
echo "│ Track phones, vehicles, assets with OwnTracks/Traccar apps. │"
|
||||||
|
echo "│ Port: 8082 (web), 5055 (OsmAnd), 5000+ (devices) │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Traccar? (y/n):" "n" INSTALL_TRACCAR
|
||||||
|
|
||||||
|
if [ "$INSTALL_TRACCAR" = "y" ] || [ "$INSTALL_TRACCAR" = "Y" ]; then
|
||||||
|
echo "Installing Traccar..."
|
||||||
|
TRACCAR_DIR="$DOCKER_DIR/traccar"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $TRACCAR_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$TRACCAR_DIR"
|
||||||
|
cd "$TRACCAR_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'TRACCAR_COMPOSE'
|
||||||
|
name: traccar
|
||||||
|
|
||||||
|
services:
|
||||||
|
traccar:
|
||||||
|
image: traccar/traccar:latest
|
||||||
|
container_name: traccar
|
||||||
|
hostname: traccar
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./logs:/opt/traccar/logs:rw
|
||||||
|
- ./data:/opt/traccar/data:rw
|
||||||
|
- ./config/traccar.xml:/opt/traccar/conf/traccar.xml:ro
|
||||||
|
ports:
|
||||||
|
- "8082:8082"
|
||||||
|
- "5000-5150:5000-5150"
|
||||||
|
- "5000-5150:5000-5150/udp"
|
||||||
|
TRACCAR_COMPOSE
|
||||||
|
|
||||||
|
mkdir -p logs data config
|
||||||
|
|
||||||
|
# Create basic traccar.xml config
|
||||||
|
cat > config/traccar.xml << 'TRACCAR_XML'
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!DOCTYPE properties SYSTEM 'http://java.sun.com/dtd/properties.dtd'>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<entry key='config.default'>./conf/default.xml</entry>
|
||||||
|
<entry key='database.driver'>org.h2.Driver</entry>
|
||||||
|
<entry key='database.url'>jdbc:h2:/opt/traccar/data/database</entry>
|
||||||
|
<entry key='database.user'>sa</entry>
|
||||||
|
<entry key='database.password'></entry>
|
||||||
|
</properties>
|
||||||
|
TRACCAR_XML
|
||||||
|
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$TRACCAR_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Traccar configured at $TRACCAR_DIR"
|
||||||
|
echo " Start with: cd $TRACCAR_DIR && docker compose up -d"
|
||||||
|
echo " Access at: http://localhost:8082"
|
||||||
|
echo " Default: admin@admin.com / admin (change immediately!)"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- PORTAINER ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ PORTAINER - Docker management web UI │"
|
||||||
|
echo "│ Manage containers, images, volumes via browser. │"
|
||||||
|
echo "│ Port: 9443 (https), 9000 (http) │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Portainer? (y/n):" "n" INSTALL_PORTAINER
|
||||||
|
|
||||||
|
if [ "$INSTALL_PORTAINER" = "y" ] || [ "$INSTALL_PORTAINER" = "Y" ]; then
|
||||||
|
echo "Installing Portainer..."
|
||||||
|
PORTAINER_DIR="$DOCKER_DIR/portainer"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $PORTAINER_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$PORTAINER_DIR"
|
||||||
|
cd "$PORTAINER_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'PORTAINER_COMPOSE'
|
||||||
|
name: portainer
|
||||||
|
|
||||||
|
services:
|
||||||
|
portainer:
|
||||||
|
image: portainer/portainer-ce:latest
|
||||||
|
container_name: portainer
|
||||||
|
hostname: portainer
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./data:/data
|
||||||
|
ports:
|
||||||
|
- "9000:9000"
|
||||||
|
- "9443:9443"
|
||||||
|
PORTAINER_COMPOSE
|
||||||
|
|
||||||
|
mkdir -p data
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$PORTAINER_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Portainer configured at $PORTAINER_DIR"
|
||||||
|
echo " Start with: cd $PORTAINER_DIR && docker compose up -d"
|
||||||
|
echo " Access at: https://localhost:9443"
|
||||||
|
echo " Create admin account on first visit"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# KOPIA BACKUP FOR DOCKER CONTAINERS
|
||||||
|
# ============================================================================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "DOCKER CONTAINER BACKUP (Kopia)"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
echo "Backup all Docker containers (configs, databases, app data) to your"
|
||||||
|
echo "backup drives. Essential for disaster recovery - if your OS drive"
|
||||||
|
echo "fails, you can restore everything including:"
|
||||||
|
echo " • Immich memories, facial recognition data"
|
||||||
|
echo " • Emby/Jellyfin metadata, watch history"
|
||||||
|
echo " • Minecraft worlds, mods, permissions"
|
||||||
|
echo " • All app configs, users, and databases"
|
||||||
|
echo ""
|
||||||
|
prompt_yn "Set up Kopia container backup? (y/n):" "n" INSTALL_KOPIA
|
||||||
|
|
||||||
|
if [ "$INSTALL_KOPIA" = "y" ] || [ "$INSTALL_KOPIA" = "Y" ]; then
|
||||||
|
echo "Installing Kopia backup..."
|
||||||
|
KOPIA_DIR="$DOCKER_DIR/kopia"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $KOPIA_DIR"
|
||||||
|
else
|
||||||
|
mkdir -p "$KOPIA_DIR"
|
||||||
|
cd "$KOPIA_DIR"
|
||||||
|
|
||||||
|
KOPIA_PASSWORD=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 24)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Select backup destination(s):"
|
||||||
|
echo " Backups will be stored in ~/drives/{backup-drive}/kopia-repo/"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# List available backup drives
|
||||||
|
echo "Available mount points in ~/drives/:"
|
||||||
|
ls -1 "$ACTUAL_HOME/drives/" 2>/dev/null | grep -v "^primary$" || echo " (none found - set up drives first)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
prompt_text "Backup drive name [default: backup1]:" "backup1" KOPIA_BACKUP_DRIVE
|
||||||
|
|
||||||
|
KOPIA_REPO="$ACTUAL_HOME/drives/$KOPIA_BACKUP_DRIVE/kopia-repo"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << KOPIA_COMPOSE
|
||||||
|
name: kopia
|
||||||
|
|
||||||
|
services:
|
||||||
|
kopia:
|
||||||
|
image: kopia/kopia:latest
|
||||||
|
container_name: kopia
|
||||||
|
hostname: kopia
|
||||||
|
restart: unless-stopped
|
||||||
|
privileged: true
|
||||||
|
devices:
|
||||||
|
- /dev/fuse:/dev/fuse:rwm
|
||||||
|
environment:
|
||||||
|
- TZ=$(cat /etc/timezone 2>/dev/null || echo "UTC")
|
||||||
|
- KOPIA_PASSWORD=\${KOPIA_PASSWORD}
|
||||||
|
command: >
|
||||||
|
server start
|
||||||
|
--tls-generate-cert
|
||||||
|
--disable-csrf-token-checks
|
||||||
|
--address=0.0.0.0:51515
|
||||||
|
--server-username=admin
|
||||||
|
--server-password=\${KOPIA_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- ./config:/app/config
|
||||||
|
- ./cache:/app/cache
|
||||||
|
- ./logs:/app/logs
|
||||||
|
- $DOCKER_DIR:/data/docker:ro
|
||||||
|
- $KOPIA_REPO:/repository
|
||||||
|
- ./tmp:/tmp:shared
|
||||||
|
ports:
|
||||||
|
- "51515:51515"
|
||||||
|
KOPIA_COMPOSE
|
||||||
|
|
||||||
|
cat > .env << KOPIA_ENV
|
||||||
|
KOPIA_PASSWORD=$KOPIA_PASSWORD
|
||||||
|
KOPIA_ENV
|
||||||
|
|
||||||
|
mkdir -p config cache logs tmp
|
||||||
|
mkdir -p "$KOPIA_REPO"
|
||||||
|
|
||||||
|
# Create backup script
|
||||||
|
cat > backup-containers.sh << 'BACKUP_SCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# Backup all Docker containers using Kopia
|
||||||
|
|
||||||
|
DOCKER_DIR="$HOME/docker"
|
||||||
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||||
|
|
||||||
|
echo "=== Docker Container Backup: $TIMESTAMP ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Stop containers before backup for consistency (optional)
|
||||||
|
read -p "Stop containers during backup for consistency? (y/n): " STOP_CONTAINERS
|
||||||
|
|
||||||
|
if [ "$STOP_CONTAINERS" = "y" ]; then
|
||||||
|
echo "Stopping containers..."
|
||||||
|
for dir in "$DOCKER_DIR"/*/; do
|
||||||
|
if [ -f "$dir/docker-compose.yml" ]; then
|
||||||
|
echo " Stopping $(basename $dir)..."
|
||||||
|
(cd "$dir" && docker compose stop) 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Running Kopia backup..."
|
||||||
|
docker exec kopia kopia snapshot create /data/docker --description "Container backup $TIMESTAMP"
|
||||||
|
|
||||||
|
if [ "$STOP_CONTAINERS" = "y" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Restarting containers..."
|
||||||
|
for dir in "$DOCKER_DIR"/*/; do
|
||||||
|
if [ -f "$dir/docker-compose.yml" ]; then
|
||||||
|
echo " Starting $(basename $dir)..."
|
||||||
|
(cd "$dir" && docker compose start) 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Backup Complete ==="
|
||||||
|
docker exec kopia kopia snapshot list /data/docker --max-results 5
|
||||||
|
BACKUP_SCRIPT
|
||||||
|
|
||||||
|
# Create restore script
|
||||||
|
cat > restore-containers.sh << 'RESTORE_SCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# Restore Docker containers from Kopia backup
|
||||||
|
|
||||||
|
echo "=== Docker Container Restore ==="
|
||||||
|
echo ""
|
||||||
|
echo "Available snapshots:"
|
||||||
|
docker exec kopia kopia snapshot list /data/docker
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "To restore a specific snapshot:"
|
||||||
|
echo " docker exec kopia kopia restore <snapshot-id> /tmp/restore"
|
||||||
|
echo " Then copy files from ~/docker/kopia/tmp/restore/ to ~/docker/"
|
||||||
|
echo ""
|
||||||
|
echo "To mount snapshots for browsing:"
|
||||||
|
echo " docker exec kopia kopia mount all /tmp/mnt &"
|
||||||
|
echo " Then browse: ~/docker/kopia/tmp/mnt/"
|
||||||
|
RESTORE_SCRIPT
|
||||||
|
|
||||||
|
chmod +x backup-containers.sh restore-containers.sh
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$KOPIA_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Kopia backup configured at $KOPIA_DIR"
|
||||||
|
echo " Start Kopia: cd $KOPIA_DIR && docker compose up -d"
|
||||||
|
echo " Web UI: https://localhost:51515"
|
||||||
|
echo " Username: admin"
|
||||||
|
echo " Password: $KOPIA_PASSWORD (saved in .env)"
|
||||||
|
echo ""
|
||||||
|
echo " Repository at: $KOPIA_REPO"
|
||||||
|
echo ""
|
||||||
|
echo " Backup now: cd $KOPIA_DIR && ./backup-containers.sh"
|
||||||
|
echo " Restore: cd $KOPIA_DIR && ./restore-containers.sh"
|
||||||
|
echo ""
|
||||||
|
echo " ⚠️ SAVE YOUR KOPIA PASSWORD! Without it, backups cannot be restored."
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# IMPORT/RESTORE CONTAINERS
|
||||||
|
# ============================================================================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "IMPORT CONTAINERS FROM BACKUP"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
echo "If you have a previous Kopia backup, you can import/restore your"
|
||||||
|
echo "Docker containers from a backup drive."
|
||||||
|
echo ""
|
||||||
|
prompt_yn "Import containers from a Kopia backup? (y/n):" "n" IMPORT_CONTAINERS
|
||||||
|
|
||||||
|
if [ "$IMPORT_CONTAINERS" = "y" ] || [ "$IMPORT_CONTAINERS" = "Y" ]; then
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would prompt for backup location and restore containers"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
prompt_text "Path to Kopia repository [e.g., /home/user/drives/backup1/kopia-repo]:" "" IMPORT_REPO
|
||||||
|
|
||||||
|
if [ -d "$IMPORT_REPO" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Repository found. To restore:"
|
||||||
|
echo ""
|
||||||
|
echo "1. Start Kopia with this repository:"
|
||||||
|
echo " docker run -it --rm -v $IMPORT_REPO:/repository -v $DOCKER_DIR:/restore kopia/kopia repository connect filesystem --path=/repository"
|
||||||
|
echo ""
|
||||||
|
echo "2. List available snapshots:"
|
||||||
|
echo " docker run -it --rm -v $IMPORT_REPO:/repository kopia/kopia snapshot list"
|
||||||
|
echo ""
|
||||||
|
echo "3. Restore a snapshot:"
|
||||||
|
echo " docker run -it --rm -v $IMPORT_REPO:/repository -v $DOCKER_DIR:/restore kopia/kopia restore <snapshot-id> /restore"
|
||||||
|
echo ""
|
||||||
|
echo "4. Start your containers:"
|
||||||
|
echo " for dir in ~/docker/*/; do (cd \"\$dir\" && docker compose up -d); done"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "Repository not found at $IMPORT_REPO"
|
||||||
|
echo "Make sure your backup drive is mounted and try again."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo "Docker applications configured in: $DOCKER_DIR"
|
echo "Docker applications configured in: $DOCKER_DIR"
|
||||||
|
|||||||
Reference in New Issue
Block a user