Skip to content

Instantly share code, notes, and snippets.

@thanosa75
Created September 8, 2025 09:56
Show Gist options
  • Save thanosa75/a945e25d9cf49bdc9f48b1549661a259 to your computer and use it in GitHub Desktop.
Save thanosa75/a945e25d9cf49bdc9f48b1549661a259 to your computer and use it in GitHub Desktop.
Creates a mountpoint for a JuiceFS B2(Backblaze) backed mountpoint. Needs REDIS and AWS CLI, environment variables to be configured
#!/bin/bash
# JuiceFS Setup Script for Debian 13 with BackBlaze B2 and REDIS
# This script sets up JuiceFS with BackBlaze B2 as object storage and REDIS as metadata backend
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration variables - MODIFY THESE
JUICEFS_NAME="jfsmountpoint" # Name for your JuiceFS filesystem
MOUNT_POINT="/mnt/jfs" # Mount point directory
REDIS_URL="redis://localhost:6379/1" # REDIS connection URL (database 1)
# BackBlaze B2 Configuration - SET THESE ENVIRONMENT VARIABLES
# export B2_APPLICATION_KEY_ID="your_key_id"
# export B2_APPLICATION_KEY="your_application_key"
# export B2_BUCKET_NAME="your-bucket-name"
# export B2_ENDPOINT="https://s3.us-west-004.backblazeb2.com" # Adjust region as needed
# export AWS_REGION="us-west-004" # adjust region here as well
print_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Check if running as root for some operations
check_root() {
if [ "$EUID" -ne 0 ]; then
print_error "This script needs to be run as root for mounting operations."
echo "Run with: sudo $0"
exit 1
fi
}
# Validate environment variables
validate_env() {
print_step "Validating environment variables..."
if [ -z "$B2_APPLICATION_KEY_ID" ]; then
print_error "B2_APPLICATION_KEY_ID environment variable not set"
print_error "Set it with: export B2_APPLICATION_KEY_ID='your_key_id'"
exit 1
fi
if [ -z "$B2_APPLICATION_KEY" ]; then
print_error "B2_APPLICATION_KEY environment variable not set"
print_error "Set it with: export B2_APPLICATION_KEY='your_application_key'"
exit 1
fi
if [ -z "$B2_BUCKET_NAME" ]; then
print_error "B2_BUCKET_NAME environment variable not set"
print_error "Set it with: export B2_BUCKET_NAME='your-bucket-name'"
exit 1
fi
if [ -z "$B2_ENDPOINT" ]; then
print_warning "B2_ENDPOINT not set, using default: https://s3.us-west-004.backblazeb2.com"
export B2_ENDPOINT="https://s3.us-west-004.backblazeb2.com"
fi
if [ -z "$AWS_REGION" ]; then
print_warning "AWS_REGION not set, using default: us-west-004"
export B2_ENDPOINT="us-west-004"
fi
print_success "Environment variables validated"
}
# Install JuiceFS
install_juicefs() {
print_step "Installing JuiceFS..."
if command_exists juicefs; then
print_success "JuiceFS is already installed"
juicefs version
return
fi
# Update package list
apt-get update
# Install required dependencies
apt-get install -y curl wget fuse3
# Download latest JuiceFS binary
JUICEFS_VERSION=$(curl -s https://api.github.com/repos/juicedata/juicefs/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
print_step "Downloading JuiceFS $JUICEFS_VERSION..."
wget -O juicefs "https://github.com/juicedata/juicefs/releases/download/${JUICEFS_VERSION}/juicefs-${JUICEFS_VERSION}-linux-amd64"
# Make executable and move to system path
chmod +x juicefs
mv juicefs /usr/local/bin/
print_success "JuiceFS installed successfully"
juicefs version
}
# Check REDIS connection
check_redis() {
print_step "Checking REDIS connection..."
if ! command_exists redis-cli; then
print_error "redis-cli not found. Install redis-tools: apt-get install redis-tools"
exit 1
fi
# Test REDIS connection
if redis-cli -u "$REDIS_URL" ping | grep -q "PONG"; then
print_success "REDIS connection successful"
else
print_error "Cannot connect to REDIS at $REDIS_URL"
print_error "Make sure REDIS is running: sudo systemctl start redis-server"
exit 1
fi
}
# Format JuiceFS filesystem
format_juicefs() {
print_step "Formatting JuiceFS filesystem..."
# Construct the S3 URL for BackBlaze B2 (just the bucket name, not full URL)
S3_BUCKET="$B2_BUCKET_NAME"
# Set AWS credentials for S3 compatibility with BackBlaze B2 specifics
export AWS_ACCESS_KEY_ID="$B2_APPLICATION_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$B2_APPLICATION_KEY"
# export AWS_REGION="us-west-004" # BackBlaze B2 region, set on top of file, not here
export AWS_ENDPOINT_URL="$B2_ENDPOINT"
export AWS_S3_FORCE_PATH_STYLE="true" # Important for BackBlaze B2
export AWS_S3_DISABLE_SSL="false" # Ensure HTTPS is used
print_warning "Using endpoint $AWS_ENDPOINT"
print_warning "Using region $AWS_REGION - does this match the endpoint region?"
# Check if filesystem already exists
if juicefs status "$REDIS_URL" >/dev/null 2>&1; then
print_warning "JuiceFS filesystem '$JUICEFS_NAME' already exists"
return
fi
# Format the filesystem with BackBlaze B2 specific settings
print_step "Creating JuiceFS filesystem '$JUICEFS_NAME'..."
print_step "Using endpoint: $B2_ENDPOINT"
print_step "Using bucket: $S3_BUCKET"
print_step "Force path style: enabled"
# Try different format approaches for BackBlaze B2 compatibility
if ! juicefs format \
--storage s3 \
--bucket "$S3_BUCKET" \
--access-key "$B2_APPLICATION_KEY_ID" \
--secret-key "$B2_APPLICATION_KEY" \
--force-path-style \
"$REDIS_URL" \
"$JUICEFS_NAME" 2>/dev/null; then
print_warning "First attempt failed, trying without --force-path-style flag..."
juicefs format \
--storage s3 \
--bucket "$S3_BUCKET" \
--access-key "$B2_APPLICATION_KEY_ID" \
--secret-key "$B2_APPLICATION_KEY" \
"$REDIS_URL" \
"$JUICEFS_NAME"
fi
print_success "JuiceFS filesystem formatted successfully"
}
# Create mount point
create_mount_point() {
print_step "Creating mount point at $MOUNT_POINT..."
if [ ! -d "$MOUNT_POINT" ]; then
mkdir -p "$MOUNT_POINT"
print_success "Mount point created at $MOUNT_POINT"
else
print_warning "Mount point $MOUNT_POINT already exists"
fi
}
# Mount JuiceFS
mount_juicefs() {
print_step "Mounting JuiceFS filesystem..."
# Check if already mounted
if mountpoint -q "$MOUNT_POINT"; then
print_warning "$MOUNT_POINT is already mounted"
return
fi
# Set environment variables for mounting
export AWS_ACCESS_KEY_ID="$B2_APPLICATION_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$B2_APPLICATION_KEY"
# export AWS_REGION="us-west-004"
export AWS_ENDPOINT_URL="$B2_ENDPOINT"
# Create cache directory
mkdir -p /var/cache/juicefs
# Mount the filesystem
juicefs mount \
--background \
--cache-dir /var/cache/juicefs \
--cache-size 10240 \
"$REDIS_URL" \
"$MOUNT_POINT"
print_success "JuiceFS mounted at $MOUNT_POINT"
}
# Display filesystem info
show_info() {
print_step "JuiceFS filesystem information:"
echo ""
juicefs status "$REDIS_URL"
echo ""
echo "Mount information:"
df -h "$MOUNT_POINT"
echo ""
echo "Test the mount:"
echo " cd $MOUNT_POINT"
echo " touch test_file.txt"
echo " ls -la"
}
# Create systemd service for auto-mounting
create_systemd_service() {
print_step "Creating systemd service for auto-mounting..."
# Create environment file for systemd service
cat > /etc/juicefs/juicefs.env << EOF
AWS_ACCESS_KEY_ID=${B2_APPLICATION_KEY_ID}
AWS_SECRET_ACCESS_KEY=${B2_APPLICATION_KEY}
AWS_REGION=${AWS_REGION}
AWS_ENDPOINT_URL=${B2_ENDPOINT}
EOF
# Secure the environment file
chmod 600 /etc/juicefs/juicefs.env
# Create systemd service file
cat > /etc/systemd/system/juicefs-${JUICEFS_NAME}.service << EOF
[Unit]
Description=JuiceFS Mount for ${JUICEFS_NAME}
After=network-online.target redis.service
Wants=network-online.target
RequiresMountsFor=/var/cache/juicefs
[Service]
Type=forking
User=root
Group=root
EnvironmentFile=/etc/juicefs/juicefs.env
ExecStartPre=/bin/mkdir -p /var/cache/juicefs
ExecStartPre=/bin/mkdir -p ${MOUNT_POINT}
ExecStart=/usr/local/bin/juicefs mount --background --cache-dir /var/cache/juicefs --cache-size 10240 ${REDIS_URL} ${MOUNT_POINT}
ExecStop=/usr/local/bin/juicefs umount ${MOUNT_POINT}
Restart=on-failure
RestartSec=5
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable juicefs-${JUICEFS_NAME}.service
print_success "Systemd service created and enabled"
echo "To start: systemctl start juicefs-${JUICEFS_NAME}.service"
echo "To check status: systemctl status juicefs-${JUICEFS_NAME}.service"
echo "To view logs: journalctl -u juicefs-${JUICEFS_NAME}.service -f"
}
# Test the mount
test_mount() {
print_step "Testing JuiceFS mount..."
# Create test file
TEST_FILE="$MOUNT_POINT/juicefs_test_$(date +%s).txt"
echo "JuiceFS is working! $(date)" > "$TEST_FILE"
if [ -f "$TEST_FILE" ]; then
print_success "Test file created successfully"
echo "Content: $(cat $TEST_FILE)"
rm "$TEST_FILE"
print_success "Test file removed successfully"
else
print_error "Failed to create test file"
exit 1
fi
}
# Cleanup function for unmounting
cleanup() {
print_step "Unmounting JuiceFS..."
if mountpoint -q "$MOUNT_POINT"; then
juicefs umount "$MOUNT_POINT"
print_success "JuiceFS unmounted"
fi
}
# Show usage information
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Required environment variables:"
echo " B2_APPLICATION_KEY_ID - BackBlaze B2 application key ID"
echo " B2_APPLICATION_KEY - BackBlaze B2 application key"
echo " B2_BUCKET_NAME - BackBlaze B2 bucket name"
echo " B2_ENDPOINT - BackBlaze B2 S3 endpoint (optional)"
echo ""
echo "Example:"
echo " export B2_APPLICATION_KEY_ID='your_key_id'"
echo " export B2_APPLICATION_KEY='your_application_key'"
echo " export B2_BUCKET_NAME='your-bucket-name'"
echo " export AWS_REGION='us-west-004' # this must match the endpoint region"
echo " export B2_ENDPOINT='https://s3.us-west-004.backblazeb2.com'"
echo " sudo -E $0"
echo ""
echo "Options:"
echo " --cleanup Unmount JuiceFS only"
echo " --help Show this help message"
echo " --test Test existing mount"
}
# Backup function
backup_metadata() {
print_step "Creating metadata backup..."
BACKUP_DIR="/var/backups/juicefs"
mkdir -p "$BACKUP_DIR"
BACKUP_FILE="$BACKUP_DIR/juicefs-${JUICEFS_NAME}-$(date +%Y%m%d_%H%M%S).dump"
if redis-cli -u "$REDIS_URL" --rdb "$BACKUP_FILE"; then
print_success "Metadata backup created: $BACKUP_FILE"
else
print_warning "Failed to create metadata backup"
fi
}
# Main execution
main() {
echo "================================================================"
echo "JuiceFS Setup Script for Debian 13 with BackBlaze B2 and REDIS"
echo "================================================================"
echo ""
# Parse command line arguments
case "${1:-}" in
--cleanup)
check_root
cleanup
exit 0
;;
--help)
show_usage
exit 0
;;
--test)
check_root
if mountpoint -q "$MOUNT_POINT"; then
test_mount
else
print_error "$MOUNT_POINT is not mounted"
exit 1
fi
exit 0
;;
"")
# Normal execution
;;
*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
esac
# Check if running as root
check_root
# Validate environment
validate_env
# Create juicefs config directory
mkdir -p /etc/juicefs
# Install and setup
install_juicefs
check_redis
format_juicefs
create_mount_point
mount_juicefs
# Test the mount
test_mount
# Create backup of metadata
backup_metadata
# Optional: Create systemd service
echo ""
read -p "Create systemd service for auto-mounting? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
create_systemd_service
fi
# Show final information
show_info
echo ""
print_success "JuiceFS setup completed successfully!"
echo ""
echo "Useful commands:"
echo " juicefs info $REDIS_URL # Show filesystem info"
echo " juicefs status $REDIS_URL # Show status"
echo " juicefs umount $MOUNT_POINT # Unmount"
echo " juicefs gc $REDIS_URL # Garbage collection"
echo " juicefs fsck $REDIS_URL # File system check"
echo " $0 --test # Test the mount"
echo " $0 --cleanup # Unmount filesystem"
echo ""
echo "Log files:"
echo " /var/log/juicefs.log # JuiceFS logs"
echo " journalctl -u juicefs-$JUICEFS_NAME # Service logs"
echo ""
echo "Configuration:"
echo " Filesystem name: $JUICEFS_NAME"
echo " Mount point: $MOUNT_POINT"
echo " REDIS URL: $REDIS_URL"
echo " B2 Bucket: $B2_BUCKET_NAME"
echo " B2 Endpoint: $B2_ENDPOINT"
echo ""
}
# Set trap for cleanup on script exit (only for normal execution)
if [ "${1:-}" != "--cleanup" ]; then
trap cleanup EXIT
fi
# Run main function with all arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment