Merge pull request #16 from outis1one/claude/docker-selfhosted-apps-QFDqX

Claude/docker selfhosted apps qf dq x
This commit is contained in:
outis1one
2026-01-06 18:34:32 -05:00
committed by GitHub
2 changed files with 250 additions and 38 deletions
+25 -4
View File
@@ -283,13 +283,34 @@ If you have existing Docker containers from another setup (different directory s
### What Migration Does
1. **Scans source directory** - Auto-detects Docker directories, finds all compose files
1. **Scans source directory** - Auto-detects Docker directories on OS and mounted drives
2. **Shows containers found** - Lists each container with size
3. **Select what to migrate** - Whiptail checklist or text menu
4. **Stops containers** (optional) - Ensures clean copy of databases
5. **Copies containers** - Preserves versions, configs, and all data
6. **Starts containers** - In the new location
7. **Offers additional services** - Continue with normal install for more apps
5. **Migration method** - Copy, Symlink, or Use in-place (for mounted drives)
6. **Updates volume paths** - Detects old paths, suggests new ones, updates compose files
7. **Starts containers** - In the new location
8. **Offers additional services** - Continue with normal install for more apps
### Volume Path Updates
When migrating, the script detects volume mounts that don't exist on the new system:
```
Container: immich
Old path: /home/user1/media/driveb
Suggested: ~/drives/primary/driveb
Options:
[Enter] Accept suggested path
[S] Skip - keep original path
[path] Enter custom path
```
- Scans all docker-compose.yml files for absolute volume paths
- Only shows paths that don't exist on the current system
- Suggests `~/drives/primary/{folder}` as default
- Updates the compose file and creates the directory
### Migration vs Restore
+225 -34
View File
@@ -720,48 +720,239 @@ run_migration() {
echo ""
fi
# Step 5: Copy containers
echo "Step 5: Migrating containers"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Step 5: Decide migration method
echo "Step 5: Migration method"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Create target directory
mkdir -p "$DOCKER_DIR"
chown "$ACTUAL_USER:$ACTUAL_USER" "$DOCKER_DIR"
# Check if source is on a different drive (mounted drive, not home on OS)
SOURCE_ON_EXTERNAL=false
if [[ "$SOURCE_DOCKER_DIR" == /mnt/* ]] || [[ "$SOURCE_DOCKER_DIR" == /media/* ]] || [[ "$SOURCE_DOCKER_DIR" == */drives/* ]]; then
SOURCE_ON_EXTERNAL=true
fi
MIGRATED_COUNT=0
for container in "${SELECTED_CONTAINERS[@]}"; do
for i in "${!CONTAINERS_FOUND[@]}"; do
if [ "${CONTAINERS_FOUND[$i]}" = "$container" ]; then
source_dir="${CONTAINER_PATHS[$i]}"
target_dir="$DOCKER_DIR/$container"
MIGRATION_METHOD="copy"
if [ "$SOURCE_ON_EXTERNAL" = true ]; then
echo "Source is on a mounted drive: $SOURCE_DOCKER_DIR"
echo ""
echo "How would you like to migrate?"
echo ""
echo " [C] Copy - Copy containers to ~/docker on OS drive"
echo " Best for: old OS drive mounted temporarily"
echo ""
echo " [S] Symlink - Create ~/docker as symlink to source location"
echo " Best for: data drive you'll keep using"
echo ""
echo " [U] Use in-place - Use source location directly, no copy"
echo " Best for: already on your data drive"
echo ""
read -p "Method (C/S/U) [C]: " MIGRATION_METHOD
# Check if already exists
if [ -d "$target_dir" ]; then
echo "$container already exists at $target_dir"
read -p " Overwrite? (y/n) [n]: " OVERWRITE
if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then
echo " Skipping $container"
continue
fi
rm -rf "$target_dir"
case "${MIGRATION_METHOD^^}" in
S)
MIGRATION_METHOD="symlink"
;;
U)
MIGRATION_METHOD="use"
;;
*)
MIGRATION_METHOD="copy"
;;
esac
else
echo "Source: $SOURCE_DOCKER_DIR"
echo "Target: $DOCKER_DIR"
echo ""
echo "Will copy containers to $DOCKER_DIR"
fi
echo ""
# Handle different migration methods
case "$MIGRATION_METHOD" in
symlink)
echo "Creating symlink: $DOCKER_DIR$SOURCE_DOCKER_DIR"
echo ""
# Check if target exists
if [ -e "$DOCKER_DIR" ] || [ -L "$DOCKER_DIR" ]; then
echo "$DOCKER_DIR already exists"
read -p " Remove and create symlink? (y/n) [n]: " REMOVE_EXISTING
if [ "$REMOVE_EXISTING" = "y" ] || [ "$REMOVE_EXISTING" = "Y" ]; then
rm -rf "$DOCKER_DIR"
else
echo " Cancelled."
return 1
fi
echo " Copying $container..."
cp -a "$source_dir" "$target_dir"
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$target_dir"
((MIGRATED_COUNT++))
echo "$container migrated"
fi
done
ln -s "$SOURCE_DOCKER_DIR" "$DOCKER_DIR"
chown -h "$ACTUAL_USER:$ACTUAL_USER" "$DOCKER_DIR"
echo "✓ Symlink created"
echo " Containers stay at: $SOURCE_DOCKER_DIR"
echo " Accessible via: $DOCKER_DIR$SOURCE_DOCKER_DIR"
MIGRATED_COUNT=${#SELECTED_CONTAINERS[@]}
;;
use)
echo "Using source location directly"
echo ""
DOCKER_DIR="$SOURCE_DOCKER_DIR"
echo "✓ DOCKER_DIR set to: $DOCKER_DIR"
echo " No files copied - containers remain in place"
MIGRATED_COUNT=${#SELECTED_CONTAINERS[@]}
;;
copy|*)
echo "Copying containers to $DOCKER_DIR"
echo ""
# Create target directory
mkdir -p "$DOCKER_DIR"
chown "$ACTUAL_USER:$ACTUAL_USER" "$DOCKER_DIR"
MIGRATED_COUNT=0
for container in "${SELECTED_CONTAINERS[@]}"; do
for i in "${!CONTAINERS_FOUND[@]}"; do
if [ "${CONTAINERS_FOUND[$i]}" = "$container" ]; then
source_dir="${CONTAINER_PATHS[$i]}"
target_dir="$DOCKER_DIR/$container"
# Check if already exists
if [ -d "$target_dir" ]; then
echo "$container already exists at $target_dir"
read -p " Overwrite? (y/n) [n]: " OVERWRITE
if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then
echo " Skipping $container"
continue
fi
rm -rf "$target_dir"
fi
echo " Copying $container..."
cp -a "$source_dir" "$target_dir"
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$target_dir"
((MIGRATED_COUNT++))
echo "$container copied"
fi
done
done
;;
esac
echo ""
echo "✓ Migrated $MIGRATED_COUNT container(s)"
echo ""
# Step 6: Update volume paths
echo "Step 6: Update volume paths"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Scanning docker-compose files for volume mounts that may need updating..."
echo ""
# Find all absolute paths in volume mounts (excluding relative paths like ./ or named volumes)
PATHS_FOUND=()
PATHS_FILES=()
for container in "${SELECTED_CONTAINERS[@]}"; do
compose_file="$DOCKER_DIR/$container/docker-compose.yml"
[ -f "$compose_file" ] || compose_file="$DOCKER_DIR/$container/compose.yml"
[ -f "$compose_file" ] || continue
# Extract volume mount paths (lines with : that look like /path:/container/path)
while IFS= read -r line; do
# Match absolute paths in volume mounts (starting with /)
if [[ "$line" =~ ^[[:space:]]*-[[:space:]]*(/[^:]+): ]]; then
host_path="${BASH_REMATCH[1]}"
# Skip if it's a relative path or standard paths
if [[ "$host_path" != "./"* ]] && [[ "$host_path" != "/etc/"* ]] && [[ "$host_path" != "/var/run/"* ]]; then
# Check if this path doesn't exist on current system
if [ ! -e "$host_path" ]; then
# Avoid duplicates
if [[ ! " ${PATHS_FOUND[*]} " =~ " ${host_path} " ]]; then
PATHS_FOUND+=("$host_path")
PATHS_FILES+=("$compose_file")
fi
fi
fi
fi
done < "$compose_file"
done
echo ""
echo "✓ Migrated $MIGRATED_COUNT container(s) to $DOCKER_DIR"
echo ""
if [ ${#PATHS_FOUND[@]} -eq 0 ]; then
echo "✓ No volume paths need updating (all paths exist or are relative)"
echo ""
else
echo "Found ${#PATHS_FOUND[@]} volume path(s) that don't exist on this system:"
echo ""
# Step 6: Start migrated containers (optional)
echo "Step 6: Start containers"
# Default new base path
DEFAULT_NEW_BASE="$HOME_DIR/drives/primary"
for i in "${!PATHS_FOUND[@]}"; do
old_path="${PATHS_FOUND[$i]}"
compose_file="${PATHS_FILES[$i]}"
container_name=$(basename "$(dirname "$compose_file")")
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Container: $container_name"
echo "Old path: $old_path"
# Suggest a new path based on the old path structure
# Extract the last part of the path for suggestion
path_tail=$(basename "$old_path")
suggested_path="$DEFAULT_NEW_BASE/$path_tail"
echo "Suggested: $suggested_path"
echo ""
echo "Options:"
echo " [Enter] Accept suggested path"
echo " [S] Skip - keep original path"
echo " [path] Enter custom path"
echo ""
read -p "New path: " NEW_PATH_INPUT
case "$NEW_PATH_INPUT" in
""|" ")
new_path="$suggested_path"
;;
[Ss])
echo " Skipping - keeping original path"
continue
;;
*)
new_path="${NEW_PATH_INPUT/#\~/$HOME_DIR}"
;;
esac
# Update the compose file
echo " Updating: $old_path$new_path"
# Escape paths for sed (handle slashes)
old_escaped=$(printf '%s\n' "$old_path" | sed 's/[[\.*^$()+?{|]/\\&/g; s/\//\\\//g')
new_escaped=$(printf '%s\n' "$new_path" | sed 's/[[\.*^$()+?{|]/\\&/g; s/\//\\\//g')
sed -i "s|$old_path|$new_path|g" "$compose_file"
# Create directory if it doesn't exist
if [ ! -d "$new_path" ]; then
echo " Creating directory: $new_path"
mkdir -p "$new_path" 2>/dev/null || echo " ⚠ Could not create (may need manual creation)"
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$new_path" 2>/dev/null || true
fi
echo " ✓ Updated"
echo ""
done
echo "✓ Volume paths updated"
echo ""
fi
# Step 7: Start migrated containers (optional)
echo "Step 7: Start containers"
echo "━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
read -p "Start migrated containers? (y/n) [y]: " START_MIGRATED
@@ -777,7 +968,7 @@ run_migration() {
echo ""
fi
# Step 7: Offer additional services
# Step 8: Offer additional services
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "MIGRATION COMPLETE"