6c82958c79
- Implement React frontend with TypeScript and Tailwind CSS - Add scrappbook.de-inspired UI design with photo galleries - Implement authentication, photo viewing, and download features - Add Docker Swarm configuration with Traefik reverse proxy - Set up Drone CI/CD pipeline for automated deployments - Add monitoring stack with Prometheus and Grafana - Create comprehensive deployment documentation - Add simple local development setup with docker-compose.local.yml Features: - Password-protected galleries with expiration warnings - Responsive photo grid with lightbox viewer - Bulk download functionality - Hot reload development environment - Email testing with Mailhog - Production-ready deployment scripts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
134 lines
4.1 KiB
Bash
Executable File
134 lines
4.1 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${GREEN}Photo Sharing Platform Backup Script${NC}"
|
|
echo "===================================="
|
|
|
|
# Configuration
|
|
BACKUP_DIR="/opt/photo-sharing/backup"
|
|
STACK_NAME="photo-sharing"
|
|
RETENTION_DAYS=30
|
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
BACKUP_NAME="backup-${TIMESTAMP}"
|
|
|
|
# Create backup directory
|
|
mkdir -p $BACKUP_DIR/$BACKUP_NAME
|
|
|
|
# Function to check if service is running
|
|
check_service() {
|
|
local service=$1
|
|
if docker service ps ${STACK_NAME}_${service} --format "{{.CurrentState}}" | grep -q "Running"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Backup database
|
|
echo -e "${GREEN}Backing up database...${NC}"
|
|
if check_service "db"; then
|
|
DB_CONTAINER=$(docker ps -q -f name=${STACK_NAME}_db -f status=running | head -1)
|
|
if [ ! -z "$DB_CONTAINER" ]; then
|
|
docker exec $DB_CONTAINER pg_dumpall -U postgres > $BACKUP_DIR/$BACKUP_NAME/database.sql
|
|
echo -e "${GREEN}Database backup completed${NC}"
|
|
else
|
|
echo -e "${RED}Database container not found${NC}"
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}Database service not running, skipping...${NC}"
|
|
fi
|
|
|
|
# Backup photos
|
|
echo -e "${GREEN}Backing up photos...${NC}"
|
|
if [ -d "/opt/photo-sharing/storage" ]; then
|
|
tar -czf $BACKUP_DIR/$BACKUP_NAME/photos.tar.gz -C /opt/photo-sharing storage/
|
|
echo -e "${GREEN}Photos backup completed${NC}"
|
|
else
|
|
echo -e "${YELLOW}Photos directory not found, skipping...${NC}"
|
|
fi
|
|
|
|
# Backup application data
|
|
echo -e "${GREEN}Backing up application data...${NC}"
|
|
if [ -d "/opt/photo-sharing/data" ]; then
|
|
tar -czf $BACKUP_DIR/$BACKUP_NAME/app-data.tar.gz -C /opt/photo-sharing data/
|
|
echo -e "${GREEN}Application data backup completed${NC}"
|
|
else
|
|
echo -e "${YELLOW}Application data directory not found, skipping...${NC}"
|
|
fi
|
|
|
|
# Backup Docker volumes
|
|
echo -e "${GREEN}Backing up Docker volumes...${NC}"
|
|
for volume in $(docker volume ls -q | grep ${STACK_NAME}); do
|
|
echo "Backing up volume: $volume"
|
|
docker run --rm \
|
|
-v $volume:/data \
|
|
-v $BACKUP_DIR/$BACKUP_NAME:/backup \
|
|
alpine tar -czf /backup/volume-${volume}.tar.gz -C /data .
|
|
done
|
|
|
|
# Backup configurations
|
|
echo -e "${GREEN}Backing up configurations...${NC}"
|
|
if [ -f "../../.env.production" ]; then
|
|
cp ../../.env.production $BACKUP_DIR/$BACKUP_NAME/
|
|
fi
|
|
|
|
# Export Docker secrets (encrypted)
|
|
echo -e "${GREEN}Exporting Docker secrets info...${NC}"
|
|
docker secret ls --filter "label=com.docker.stack.namespace=$STACK_NAME" > $BACKUP_DIR/$BACKUP_NAME/secrets-list.txt
|
|
|
|
# Create backup manifest
|
|
echo -e "${GREEN}Creating backup manifest...${NC}"
|
|
cat > $BACKUP_DIR/$BACKUP_NAME/manifest.json << EOF
|
|
{
|
|
"timestamp": "$TIMESTAMP",
|
|
"stack_name": "$STACK_NAME",
|
|
"hostname": "$(hostname)",
|
|
"docker_version": "$(docker version --format '{{.Server.Version}}')",
|
|
"services": $(docker service ls --filter "label=com.docker.stack.namespace=$STACK_NAME" --format '{{json .}}' | jq -s .),
|
|
"backup_contents": [
|
|
"database.sql",
|
|
"photos.tar.gz",
|
|
"app-data.tar.gz",
|
|
"volume-*.tar.gz",
|
|
".env.production",
|
|
"secrets-list.txt"
|
|
]
|
|
}
|
|
EOF
|
|
|
|
# Compress entire backup
|
|
echo -e "${GREEN}Compressing backup...${NC}"
|
|
cd $BACKUP_DIR
|
|
tar -czf ${BACKUP_NAME}.tar.gz $BACKUP_NAME/
|
|
rm -rf $BACKUP_NAME/
|
|
|
|
# Upload to S3 (optional)
|
|
if [ ! -z "$S3_BACKUP_BUCKET" ] && command -v aws &> /dev/null; then
|
|
echo -e "${GREEN}Uploading to S3...${NC}"
|
|
aws s3 cp ${BACKUP_NAME}.tar.gz s3://${S3_BACKUP_BUCKET}/photo-sharing/
|
|
fi
|
|
|
|
# Clean up old backups
|
|
echo -e "${GREEN}Cleaning up old backups...${NC}"
|
|
find $BACKUP_DIR -name "backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
|
|
|
# Show backup summary
|
|
BACKUP_SIZE=$(du -h $BACKUP_DIR/${BACKUP_NAME}.tar.gz | cut -f1)
|
|
echo ""
|
|
echo -e "${GREEN}Backup completed successfully!${NC}"
|
|
echo -e "Backup file: $BACKUP_DIR/${BACKUP_NAME}.tar.gz"
|
|
echo -e "Backup size: $BACKUP_SIZE"
|
|
echo -e "Retention: $RETENTION_DAYS days"
|
|
|
|
# Verify backup
|
|
echo ""
|
|
echo -e "${GREEN}Verifying backup...${NC}"
|
|
tar -tzf $BACKUP_DIR/${BACKUP_NAME}.tar.gz | head -10
|
|
echo "..."
|
|
echo -e "${GREEN}Backup verification complete${NC}" |