| ← Back to Documentation Index | Main README |
This guide provides comprehensive solutions to common issues you might encounter when installing or managing your Garage cluster.
When running the garage-installer on macOS, you may see this error:
"garage-installer-macos-arm64 cannot be opened because the developer cannot be verified"
This happens because the binary is unsigned. macOS Gatekeeper prevents execution of unverified executables for security reasons.
Run this command to remove the quarantine attribute:
xattr -d com.apple.quarantine ./garage-installer-macos-arm64
chmod +x ./garage-installer-macos-arm64
./garage-installer-macos-arm64
This tells macOS to trust the downloaded binary. It’s safe because you’ve already verified it through GitHub releases.
If the command doesn’t work:
See: https://support.apple.com/guide/mac-help/apple-cant-check-app-for-malicious-software-mchleab3a043/
The installer is compiled as a standalone Deno binary. To eliminate this warning entirely would require:
This is not yet implemented but is planned for future releases.
Problem:
✖ Installation failed: [user@host:22] SSH connection failed: Unknown cipher
This occurs when the remote SSH server doesn’t support the cipher algorithms that the ssh2 library can negotiate with it.
Common Causes:
Solution:
The installer supports a wide range of ciphers including:
chacha20-poly1305@openssh.com, aes128-gcm@openssh.com, aes256-gcm@openssh.comaes128-ctr, aes192-ctr, aes256-ctraes128-cbc, aes192-cbc, aes256-cbc, 3des-cbcIf you still get this error:
ssh -Q cipher user@remote-host
ssh -v user@remote-host
Look for cipher negotiation in the output (search for “ciphers_allowed”).
# On the REMOTE server, edit SSH config:
sudo nano /etc/ssh/sshd_config
# Add this line if restrictive ciphers are set:
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes256-cbc,3des-cbc
# Restart SSH:
sudo systemctl restart ssh
ssh -vvv user@remote-host 2>&1 | grep -i cipher
And open an issue with the cipher names shown.
Problem:
Failed to read SSH key from /home/user/.ssh/id_rsa: Permission denied
Solution:
# Ensure correct permissions on SSH key
chmod 600 ~/.ssh/id_rsa
# Ensure .ssh directory is readable
chmod 700 ~/.ssh
Problem:
SSH connection timeout after 30000ms
Causes:
Solution:
# Check if host is reachable
ping -c 3 remote-host
# Check if SSH port is open
nc -zv remote-host 22
# Or with telnet
telnet remote-host 22
# Test SSH connection directly
ssh -v user@remote-host
Problem:
SSH connection failed: Permission denied (publickey)
Solution:
ssh -i ~/.ssh/id_rsa user@remote-host
authorized_keys:
ssh user@remote-host "cat ~/.ssh/authorized_keys"
authorized_keys:
ssh-copy-id -i ~/.ssh/id_rsa user@remote-host
ssh user@remote-host "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
The installer requires Docker to be installed on both remote nodes. Since Docker installation requires sudo privileges (and often interactive password entry), you must install it manually before running the installer.
Recommended: Official Docker Installation
# Update package index
sudo apt-get update
# Install dependencies
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Set up the repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Verify installation
docker --version
docker compose version
Alternative: Convenience Script
# Download and run Docker's convenience script
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
rm get-docker.sh
# Install Docker Compose plugin
sudo apt-get update
sudo apt-get install -y docker-compose-plugin
# Verify installation
docker --version
docker compose version
Post-Installation: Add User to Docker Group
# Add your user to the docker group (avoids needing sudo for docker commands)
sudo usermod -aG docker $USER
# Activate the group (choose one):
# Option 1: Log out and log back in
# Option 2: Use newgrp
newgrp docker
# Verify you can run docker without sudo
docker ps
For Debian, use the Debian repository instead:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Then follow the same apt-get install steps as Ubuntu.
RHEL / CentOS / Fedora:
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
Arch Linux:
sudo pacman -S docker docker-compose
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
Alpine Linux:
sudo apk add docker docker-compose
sudo rc-update add docker boot
sudo service docker start
sudo addgroup $USER docker
If you installed Docker using the methods above, Docker Compose is already installed as a plugin (docker compose).
Verify Docker Compose:
docker compose version
# Should output: Docker Compose version v2.x.x
If Docker Compose is missing:
The modern way (Docker Compose v2) is installed as a plugin:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y docker-compose-plugin
# Verify
docker compose version
Legacy Docker Compose v1 (not recommended):
# Only if you need the old standalone version
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
The AWS CLI is required on your local machine to validate the Garage installation.
# Using Homebrew
brew install awscli
# Verify
aws --version
# Using package manager (Ubuntu/Debian)
sudo apt-get install -y awscli
# Or using pip
pip install awscli
# Or download official installer
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
rm -rf aws awscliv2.zip
# Verify
aws --version
# Using Chocolatey
choco install awscli
# Or download MSI installer from:
# https://awscli.amazonaws.com/AWSCLIV2.msi
Before running the installer, verify all prerequisites are installed:
# On remote nodes
ssh user@node1 "docker --version && docker compose version"
ssh user@node2 "docker --version && docker compose version"
# On local machine
aws --version
Expected output:
Docker version 24.0.0 or higher
Docker Compose version v2.20.0 or higher
aws-cli/2.x.x or higher
Symptoms:
Error: SSH connection failed to node1
Causes & Solutions:
# On the remote host
sudo systemctl status sshd
sudo systemctl start sshd
sudo systemctl enable sshd
sudo ss -tlnp | grep sshd# On remote host - allow SSH
sudo ufw allow 22/tcp
# Or for custom port
sudo ufw allow YOUR_PORT/tcp
# Test basic connectivity
ping -c 3 your-node-hostname
# Test SSH port specifically
telnet your-node-hostname 22
# Or use nc
nc -zv your-node-hostname 22
Causes & Solutions:
# Copy your public key to remote host
ssh-copy-id -i ~/.ssh/id_rsa.pub user@hostname
# Or manually add to authorized_keys
cat ~/.ssh/id_rsa.pub | ssh user@hostname "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
ls -la ~/.ssh/# Private key must be 600
chmod 600 ~/.ssh/id_rsa
# .ssh directory should be 700
chmod 700 ~/.ssh
# On remote host, authorized_keys should be 600
ssh user@hostname "chmod 600 ~/.ssh/authorized_keys"
# On remote host - check SELinux
getenforce
# If enforcing, temporarily disable to test
sudo setenforce 0
# Restore proper SELinux contexts
restorecon -R -v ~/.ssh
This issue has been fixed in the installer. The installer automatically uses compatible SSH ciphers.
If you still see this error:
# On remote host, add to /etc/ssh/sshd_config
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
# Restart SSH
sudo systemctl restart sshd
ssh -V
# Should be OpenSSH 7.0+
Symptoms:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Causes & Solutions:
# Remove old host key
ssh-keygen -R hostname
# Or for specific IP
ssh-keygen -R 192.168.1.100
# Then reconnect (will prompt to accept new key)
The installer does NOT automatically install Docker because it requires sudo privileges and interactive password entry.
Solution: Install Docker manually on both nodes before running the installer. See the Installing Prerequisites section above for detailed instructions.
Quick check if Docker is installed:
docker --version
docker compose version
Solution: Install Docker Compose on both nodes. If you installed Docker using modern methods, Docker Compose should already be installed as a plugin. See Installing Prerequisites for details.
Symptoms:
Got permission denied while trying to connect to the Docker daemon socket
Causes & Solutions:
# Add user to docker group
sudo usermod -aG docker $USER
# Activate the group (choose one):
# Option A: Re-login (logout and login again)
# Option B: Use newgrp
newgrp docker
# Option C: The installer will use 'sudo docker' for this session
sudo systemctl status docker
sudo systemctl start docker
sudo systemctl enable docker
# Check socket permissions
ls -l /var/run/docker.sock
# Should be: srw-rw---- 1 root docker
# If not:
sudo chmod 660 /var/run/docker.sock
sudo chown root:docker /var/run/docker.sock
Symptoms:
Error response from daemon: Get "https://registry-1.docker.io/v2/": ...
Causes & Solutions:
# Test connectivity
ping -c 3 8.8.8.8
curl -I https://hub.docker.com
docker login
# Create or edit /etc/systemd/system/docker.service.d/http-proxy.conf
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf > /dev/null <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"
Environment="HTTPS_PROXY=https://proxy.example.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
Symptoms: Preflight checks report ports are busy.
Find what’s using the ports:
# Method 1: Using ss
sudo ss -tlnp | grep ':3900'
# Method 2: Using netstat
sudo netstat -tlnp | grep ':3900'
# Method 3: Using lsof
sudo lsof -i :3900
Solutions:
# If you see another service using the port
sudo systemctl stop service-name
# Or kill specific process
sudo kill -9 PID
# If you have a previous Garage installation
docker stop garage
docker rm garage
# Or using compose
cd ~/garage
docker compose down
Symptoms:
✖ Cannot reach node2 from node1 (ping failed)
Causes & Solutions:
# On both nodes, allow Garage RPC port (3901)
sudo ufw allow from NODE1_IP to any port 3901
sudo ufw allow from NODE2_IP to any port 3901
# Or allow all traffic between nodes
sudo ufw allow from NODE1_IP
ping -c 3 node2-hostname
ping -c 3 192.168.1.101 ```
# Check routing
ip route
traceroute node2-hostname
# Test if port 3901 is reachable
nc -zv node2-hostname 3901
# Or
telnet node2-hostname 3901
Check cluster status:
ssh user@node1
docker exec garage /garage status
Look for:
is_up: truelast_seen_secs_ago should be < 10If nodes show as down:
docker logs garage
Check logs:
docker logs garage
Common causes:
# Validate TOML syntax
cd ~/garage
docker run --rm -v $PWD:/data dxflrs/garage:v2.1.0 /garage --config /data/garage.toml --help
# Check ownership
ls -la ~/garage/data ~/garage/meta
# Fix if needed (use your UID)
id -u # Get your UID
sudo chown -R YOUR_UID:YOUR_GID ~/garage/data ~/garage/meta
Force stop:
docker stop -t 2 garage # Give it 2 seconds
docker kill garage # Force kill if needed
If still stuck:
# Restart Docker daemon
sudo systemctl restart docker
Check disk space:
df -h
Solutions:
docker system prune -a --volumes
Causes & Solutions:
docker ps -a | grep garage
docker logs garage
# Test garage command directly
docker exec garage /garage --version
Symptoms:
Error: Failed to connect nodes: already connected
This is usually harmless - nodes were already connected from a previous attempt.
If genuinely failing:
docker exec garage grep rpc_secret /etc/garage.toml
Symptoms:
Error: Failed to apply layout: Invalid version
Causes & Solutions:
# Check current layout
docker exec garage /garage layout show
# Note the version number, increment by 1
docker exec garage /garage layout apply --version X
Check status:
docker exec garage /garage status
Common causes:
docker exec garage /garage layout showThis has been fixed in the installer - it now automatically configures path-style addressing.
Manual fix if needed:
# Add to ~/.aws/config
[default]
region = garage
[profile default]
s3 =
addressing_style = path
Or set per-command:
aws configure set default.s3.addressing_style path
Solution:
# Set region to 'garage'
aws configure set default.region garage
Install AWS CLI:
# macOS
brew install awscli
# Ubuntu/Debian
sudo apt-get install awscli
# Python pip
pip install awscli
Symptoms:
Could not connect to the endpoint URL: "http://node1:3900/"
Causes & Solutions:
# Test connectivity
curl http://node1:3900/
# Should return XML error (AccessDenied is normal)
aws s3 ls --endpoint-url http://192.168.1.100:3900
# On Garage nodes
sudo ufw allow 3900/tcp
# Forward local port 3900 to remote
ssh -L 3900:localhost:3900 user@node1
# Then use localhost
aws s3 ls --endpoint-url http://localhost:3900
For comprehensive AWS CLI configuration, see AWS CLI Configuration Guide.
The installer saves its progress to .garage-installer-state.json. You can use this to resume or clean up.
Resume interrupted installation:
Clean up after failed installation:
Manual cleanup if needed:
# On each node
ssh user@node
# Stop and remove container
docker stop garage
docker rm garage
# Remove configuration and data
rm -rf ~/garage
# Check for any leftover volumes
docker volume ls | grep garage
docker volume rm VOLUME_NAME
Symptoms:
Error: Failed to parse state file
Solution:
# Delete the state file and start fresh
rm .garage-installer-state.json
Solution:
The installer writes to garage-installer.log in the current directory.
# View the log
tail -f garage-installer.log
# Search for errors
grep ERROR garage-installer.log
# View real-time logs
docker logs -f garage
# View recent logs
docker logs --tail 100 garage
# Look for specific errors
docker logs garage 2>&1 | grep -i error
# Comprehensive cluster status
docker exec garage /garage status
# Layout information
docker exec garage /garage layout show
# Key and bucket information
docker exec garage /garage bucket list
docker exec garage /garage key list
“Fsyncing to disk…” (INFO)
“Metadata engine is initialized” (INFO)
“Connection refused” when connecting to RPC
“Layout version mismatch”
garage layout show on both nodessudo apt-get update && sudo apt-get upgrade
docker exec garage /garage statusdocker logs garage | grep -i errordf -h| ← Back to Documentation Index | Main README |