mirror of
https://github.com/bigbeartechworld/big-bear-scripts.git
synced 2026-03-31 06:33:56 -04:00
Add CasaOS Docker API version fix script (#55)
Introduces a script and documentation to resolve Docker API version incompatibility and related runtime errors for CasaOS, including overlay2 permission issues and CVE-2025-52881 AppArmor problems in LXC/Proxmox environments. The script automates Docker downgrade, containerd version management, permission fixes, and service restarts to restore compatibility and stability.
This commit is contained in:
142
casaos-fix-docker-api-version/README.md
Normal file
142
casaos-fix-docker-api-version/README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Fix Docker API Version Error for CasaOS
|
||||
|
||||
This script fixes common Docker errors with CasaOS including:
|
||||
- `Error response from daemon: client version 1.43 is too old. Minimum supported API version is 1.44`
|
||||
- `OCI runtime create failed: runc create failed: unable to start container process: error during container init: open sysctl net.ipv4.ip_unprivileged_port_start file: reopen fd 8: permission denied`
|
||||
- Docker permission issues and corrupted overlay2 storage
|
||||
- CVE-2025-52881 AppArmor issues in LXC/Proxmox environments
|
||||
|
||||
## The Problem
|
||||
|
||||
These errors commonly occur with **CasaOS** when:
|
||||
1. Docker gets upgraded to a very recent version (API 1.44+) that is incompatible with CasaOS's older Docker client
|
||||
2. Docker overlay2 filesystem permissions become corrupted
|
||||
3. Container runtime state becomes inconsistent
|
||||
4. **NEW**: containerd.io 1.7.28-2 or newer causes AppArmor permission errors in LXC/Proxmox containers
|
||||
|
||||
CasaOS uses Docker API 1.43, and when the system Docker gets auto-upgraded or the storage becomes corrupted, it breaks compatibility.
|
||||
|
||||
### Special Note for LXC/Proxmox Users
|
||||
|
||||
If you're running CasaOS or Docker in an LXC container (common with Proxmox), you may encounter the `permission denied` error after updating containerd. This is caused by **CVE-2025-52881** security patches that conflict with AppArmor profiles in nested containers.
|
||||
|
||||
**The error looks like:**
|
||||
```
|
||||
failed to create shim task: OCI runtime create failed: runc create failed:
|
||||
unable to start container process: error during container init:
|
||||
open sysctl net.ipv4.ip_unprivileged_port_start file: reopen fd 8: permission denied
|
||||
```
|
||||
|
||||
This script automatically detects LXC environments and installs **containerd.io 1.7.28-1** (the last version before the breaking change) to prevent this issue.
|
||||
|
||||
**References:**
|
||||
- GitHub Issue: https://github.com/opencontainers/runc/issues/4968
|
||||
- Proxmox Forum: https://forum.proxmox.com/threads/docker-inside-lxc-net-ipv4-ip_unprivileged_port_start-error.175437/
|
||||
|
||||
## What does this script do?
|
||||
|
||||
- Detects your operating system (Debian/Ubuntu-based)
|
||||
- **Detects LXC/Proxmox environment** and adjusts containerd version accordingly
|
||||
- Checks if CasaOS is installed
|
||||
- Stops CasaOS services temporarily (if installed)
|
||||
- Cleans Docker runtime state and fixes permissions
|
||||
- Fixes overlay2 directory permissions
|
||||
- Downgrades Docker to version 24.0.7 (compatible with both CasaOS and modern systems)
|
||||
- **Installs containerd.io 1.7.28-1** in LXC/Proxmox to avoid CVE-2025-52881 AppArmor issues
|
||||
- Configures Docker daemon with proper settings
|
||||
- Holds Docker packages to prevent automatic upgrades
|
||||
- Removes standalone docker-compose if present
|
||||
- Installs Docker Compose plugin
|
||||
- Restarts Docker service properly
|
||||
- Restarts CasaOS services (if installed)
|
||||
- **Intelligently detects and fixes** the sysctl permission denied error
|
||||
|
||||
## Run command
|
||||
|
||||
```bash
|
||||
bash -c "$(wget -qLO - https://raw.githubusercontent.com/bigbeartechworld/big-bear-scripts/master/casaos-fix-docker-api-version/run.sh)"
|
||||
```
|
||||
|
||||
## Can't Resolve Domain
|
||||
|
||||
To resolve this issue, please follow these steps:
|
||||
|
||||
1. Copy the contents of run.sh from this repository.
|
||||
2. Create a file named run.sh on your server.
|
||||
3. Execute the following command on your server:
|
||||
|
||||
```bash
|
||||
bash run.sh
|
||||
```
|
||||
|
||||
## What causes these errors?
|
||||
|
||||
These errors occur when:
|
||||
- Docker gets auto-upgraded to version 25+ or 26+ (API 1.44+)
|
||||
- CasaOS still uses Docker API 1.43 in older versions
|
||||
- There's a version mismatch between CasaOS's Docker client and the system's Docker daemon
|
||||
- System updates automatically upgrade Docker without considering CasaOS compatibility
|
||||
- Docker overlay2 storage permissions become corrupted
|
||||
- Container runtime (runc/containerd) state becomes inconsistent
|
||||
- Improper system shutdowns or Docker crashes leave stale state files
|
||||
- **containerd.io 1.7.28-2 or newer** in LXC/Proxmox (CVE-2025-52881 AppArmor conflict)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Debian or Ubuntu-based Linux distribution
|
||||
- Sudo privileges or root access
|
||||
- Active internet connection
|
||||
- CasaOS installed (optional - script works without it too)
|
||||
|
||||
## After running the script
|
||||
|
||||
You can verify the fix by running:
|
||||
```bash
|
||||
docker version
|
||||
```
|
||||
|
||||
Both the client and server API versions should now be compatible. The script installs Docker 24.0.7 which:
|
||||
- Supports API version 1.43 (compatible with older CasaOS)
|
||||
- Is stable and well-tested
|
||||
- Is held at this version to prevent auto-upgrades
|
||||
|
||||
## Preventing future issues
|
||||
|
||||
The script automatically holds Docker packages to prevent automatic upgrades:
|
||||
```bash
|
||||
sudo apt-mark hold docker-ce docker-ce-cli containerd.io
|
||||
```
|
||||
|
||||
**Important for LXC/Proxmox users:** The script holds containerd.io at version 1.7.28-1 to prevent the CVE-2025-52881 AppArmor issue. Do not upgrade containerd until this issue is resolved upstream.
|
||||
|
||||
If you want to allow Docker upgrades in the future (after confirming CasaOS compatibility), run:
|
||||
```bash
|
||||
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io
|
||||
```
|
||||
|
||||
⚠️ **Warning for LXC users**: Before unholdingcontainerd.io, check if the AppArmor issue has been fixed:
|
||||
- Check: https://github.com/opencontainers/runc/issues/4968
|
||||
- Or test in a non-production environment first
|
||||
|
||||
## Version Information
|
||||
|
||||
- Docker CE: 24.0.7
|
||||
- Docker API: 1.43 compatible
|
||||
- containerd.io: 1.7.28-1 (for LXC/Proxmox environments)
|
||||
- Works with CasaOS 0.4.x series
|
||||
|
||||
## Alternative Solutions for LXC/Proxmox (Advanced)
|
||||
|
||||
If you prefer not to downgrade containerd, you can modify the LXC container configuration on the Proxmox host:
|
||||
|
||||
**Option 1: Disable AppArmor for the container** (in `/etc/pve/lxc/$CTID.conf`):
|
||||
```
|
||||
lxc.apparmor.profile: unconfined
|
||||
lxc.mount.entry: /dev/null sys/module/apparmor/parameters/enabled none bind 0 0
|
||||
```
|
||||
|
||||
**Option 2: Wait for upstream fixes:**
|
||||
- Proxmox/LXC to update their AppArmor profiles
|
||||
- containerd/runc to implement workarounds
|
||||
|
||||
This script uses the downgrade approach as it's the safest and most reliable solution that doesn't require host-level configuration changes.
|
||||
853
casaos-fix-docker-api-version/run.sh
Executable file
853
casaos-fix-docker-api-version/run.sh
Executable file
@@ -0,0 +1,853 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# BigBear CasaOS Docker Client Version Fix
|
||||
# Script to fix Docker client version 1.43 is too old error for CasaOS
|
||||
# This script downgrades Docker to a version compatible with CasaOS
|
||||
#
|
||||
# GitHub: https://github.com/BigBearTechWorld
|
||||
# Community: https://community.bigbeartechworld.com
|
||||
# Support: https://ko-fi.com/bigbeartechworld
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "BigBear CasaOS Docker Version Fix Script"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Here are some links:"
|
||||
echo "https://community.bigbeartechworld.com"
|
||||
echo "https://github.com/BigBearTechWorld"
|
||||
echo ""
|
||||
echo "If you would like to support me, please consider buying me a tea:"
|
||||
echo "https://ko-fi.com/bigbeartechworld"
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Compatible Docker versions for CasaOS
|
||||
# Using Docker 24.x series which supports API 1.43 (older CasaOS versions)
|
||||
# but is also compatible with API 1.44 (newer Docker daemons)
|
||||
readonly DOCKER_CE_VERSION="5:24.0.7-1~"
|
||||
readonly DOCKER_CLI_VERSION="5:24.0.7-1~"
|
||||
# Using containerd.io 1.7.28-1 to avoid CVE-2025-52881 AppArmor issues in LXC/Proxmox
|
||||
# Version 1.7.28-2 and newer cause "permission denied" errors on sysctl in nested containers
|
||||
readonly CONTAINERD_VERSION="1.7.28-1"
|
||||
|
||||
# Function to display current versions
|
||||
display_versions() {
|
||||
echo "Current Docker versions:"
|
||||
if command -v docker &>/dev/null; then
|
||||
docker version 2>&1 || echo "Unable to get full version info due to API mismatch"
|
||||
echo ""
|
||||
else
|
||||
echo "Docker command not found"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if running as root or with sudo
|
||||
check_sudo() {
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
SUDO=""
|
||||
else
|
||||
SUDO="sudo"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to detect the OS
|
||||
detect_os() {
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
OS=$ID
|
||||
VERSION_CODENAME=${VERSION_CODENAME:-$(lsb_release -cs 2>/dev/null)}
|
||||
else
|
||||
echo "Cannot detect OS. This script supports Debian/Ubuntu-based systems."
|
||||
exit 1
|
||||
fi
|
||||
echo "Detected OS: $OS ${VERSION_CODENAME}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to check if CasaOS is installed
|
||||
check_casaos() {
|
||||
if command -v casaos &>/dev/null; then
|
||||
echo "CasaOS is installed: $(casaos -v 2>/dev/null || echo 'version unknown')"
|
||||
return 0
|
||||
else
|
||||
echo "CasaOS not detected."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to detect if running in LXC/Proxmox container
|
||||
check_lxc_environment() {
|
||||
if [ -f /proc/1/environ ]; then
|
||||
if grep -qa "container=lxc" /proc/1/environ 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Alternative check: systemd-detect-virt
|
||||
if command -v systemd-detect-virt &>/dev/null; then
|
||||
if systemd-detect-virt -c | grep -q "lxc"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to check containerd.io version
|
||||
check_containerd_version() {
|
||||
if ! command -v containerd &>/dev/null; then
|
||||
echo "not_installed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get installed version
|
||||
local version=$(dpkg -l | grep containerd.io | awk '{print $3}' | head -n1)
|
||||
echo "$version"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to stop CasaOS services
|
||||
stop_casaos_services() {
|
||||
echo "Stopping CasaOS services..."
|
||||
|
||||
CASA_SERVICES=(
|
||||
"casaos-gateway.service"
|
||||
"casaos-message-bus.service"
|
||||
"casaos-user-service.service"
|
||||
"casaos-local-storage.service"
|
||||
"casaos-app-management.service"
|
||||
"casaos.service"
|
||||
)
|
||||
|
||||
for SERVICE in "${CASA_SERVICES[@]}"; do
|
||||
if $SUDO systemctl is-active --quiet "$SERVICE" 2>/dev/null; then
|
||||
echo " Stopping $SERVICE..."
|
||||
$SUDO systemctl stop "$SERVICE" || true
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to start CasaOS services
|
||||
start_casaos_services() {
|
||||
echo "Starting CasaOS services..."
|
||||
|
||||
CASA_SERVICES=(
|
||||
"casaos-gateway.service"
|
||||
"casaos-message-bus.service"
|
||||
"casaos-user-service.service"
|
||||
"casaos-local-storage.service"
|
||||
"casaos-app-management.service"
|
||||
"casaos.service"
|
||||
)
|
||||
|
||||
for SERVICE in "${CASA_SERVICES[@]}"; do
|
||||
if $SUDO systemctl is-enabled --quiet "$SERVICE" 2>/dev/null; then
|
||||
echo " Starting $SERVICE..."
|
||||
$SUDO systemctl start "$SERVICE" || true
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to validate daemon.json
|
||||
validate_daemon_json() {
|
||||
local daemon_json="/etc/docker/daemon.json"
|
||||
|
||||
if [ ! -f "$daemon_json" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if it's valid JSON
|
||||
if command -v python3 &>/dev/null; then
|
||||
if ! python3 -m json.tool "$daemon_json" > /dev/null 2>&1; then
|
||||
echo "ERROR: daemon.json is not valid JSON"
|
||||
return 1
|
||||
fi
|
||||
elif command -v jq &>/dev/null; then
|
||||
if ! jq empty "$daemon_json" > /dev/null 2>&1; then
|
||||
echo "ERROR: daemon.json is not valid JSON"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to detect and fix Docker errors
|
||||
detect_and_fix_docker_errors() {
|
||||
echo "Analyzing Docker error logs..."
|
||||
|
||||
# Get recent Docker logs
|
||||
local docker_logs=$($SUDO journalctl -u docker --no-pager -n 100 2>/dev/null)
|
||||
|
||||
# Check for specific errors and apply fixes
|
||||
|
||||
# Error 1: overlay2.override_kernel_check unknown option
|
||||
if echo "$docker_logs" | grep -q "unknown option overlay2.override_kernel_check"; then
|
||||
echo "Detected: Invalid overlay2.override_kernel_check option in daemon.json"
|
||||
echo "Fix: Removing invalid storage-opts from daemon.json..."
|
||||
|
||||
if [ -f /etc/docker/daemon.json ]; then
|
||||
# Backup the file
|
||||
$SUDO cp /etc/docker/daemon.json /etc/docker/daemon.json.backup.$(date +%Y%m%d_%H%M%S)
|
||||
|
||||
# Remove the invalid option using python or sed
|
||||
if command -v python3 &>/dev/null; then
|
||||
$SUDO python3 << 'EOF'
|
||||
import json
|
||||
try:
|
||||
with open('/etc/docker/daemon.json', 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
# Remove storage-opts if it contains the invalid option
|
||||
if 'storage-opts' in config:
|
||||
config['storage-opts'] = [opt for opt in config['storage-opts']
|
||||
if 'overlay2.override_kernel_check' not in opt]
|
||||
if not config['storage-opts']:
|
||||
del config['storage-opts']
|
||||
|
||||
with open('/etc/docker/daemon.json', 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
print("Fixed: Removed invalid storage-opts")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
EOF
|
||||
else
|
||||
# Fallback: create a simple daemon.json
|
||||
$SUDO tee /etc/docker/daemon.json > /dev/null <<EOL
|
||||
{
|
||||
"storage-driver": "overlay2"
|
||||
}
|
||||
EOL
|
||||
fi
|
||||
echo "daemon.json has been fixed"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Error 2: Permission denied errors
|
||||
if echo "$docker_logs" | grep -q "permission denied"; then
|
||||
echo "Detected: Permission errors in Docker"
|
||||
echo "Fix: Resetting Docker directory permissions..."
|
||||
clean_docker_state
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Error 3: Failed to create shim task / OCI runtime errors (including sysctl permission denied)
|
||||
if echo "$docker_logs" | grep -q -E "failed to create shim task|OCI runtime create failed"; then
|
||||
echo "Detected: Container runtime errors"
|
||||
|
||||
# Check specifically for the CVE-2025-52881 AppArmor sysctl issue
|
||||
if echo "$docker_logs" | grep -q "open sysctl.*permission denied"; then
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "CRITICAL: CVE-2025-52881 AppArmor Issue Detected"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "This error is caused by containerd.io 1.7.28-2 or newer in LXC/Proxmox containers."
|
||||
echo "The security patch for CVE-2025-52881 conflicts with AppArmor profiles."
|
||||
echo ""
|
||||
|
||||
if check_lxc_environment; then
|
||||
echo "✓ LXC/Proxmox environment detected"
|
||||
echo ""
|
||||
local current_containerd=$(check_containerd_version)
|
||||
echo "Current containerd.io version: $current_containerd"
|
||||
echo ""
|
||||
|
||||
# Check if we need to downgrade containerd
|
||||
if [[ "$current_containerd" =~ 1\.7\.(28-2|29) ]] || [[ "$current_containerd" =~ 1\.7\.(3[0-9]) ]]; then
|
||||
echo "This version causes the sysctl permission error."
|
||||
echo "The script will downgrade containerd.io to version 1.7.28-1"
|
||||
echo ""
|
||||
echo "Note: This is the recommended workaround until LXC/Proxmox updates their AppArmor profiles."
|
||||
echo "See: https://github.com/opencontainers/runc/issues/4968"
|
||||
echo ""
|
||||
return 1 # Signal that we need to proceed with the full installation
|
||||
fi
|
||||
else
|
||||
echo "⚠ Not running in LXC/Proxmox - this error is unexpected"
|
||||
echo "Please check your Docker and containerd configuration."
|
||||
fi
|
||||
echo ""
|
||||
else
|
||||
# Generic runtime error - try cleaning runtime state
|
||||
echo "Fix: Cleaning runtime state..."
|
||||
|
||||
# Clean containerd
|
||||
$SUDO systemctl stop docker 2>/dev/null || true
|
||||
$SUDO systemctl stop containerd 2>/dev/null || true
|
||||
|
||||
if [ -d /run/containerd ]; then
|
||||
$SUDO rm -rf /run/containerd/* 2>/dev/null || true
|
||||
fi
|
||||
|
||||
$SUDO systemctl start containerd 2>/dev/null || true
|
||||
sleep 2
|
||||
echo "Runtime state cleaned"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Error 4: Address already in use
|
||||
if echo "$docker_logs" | grep -q "address already in use"; then
|
||||
echo "Detected: Port conflict"
|
||||
echo "Fix: Cleaning stale Docker sockets..."
|
||||
|
||||
$SUDO systemctl stop docker 2>/dev/null || true
|
||||
$SUDO systemctl stop docker.socket 2>/dev/null || true
|
||||
|
||||
# Remove stale sockets
|
||||
$SUDO rm -f /var/run/docker.sock
|
||||
$SUDO rm -f /var/run/docker.pid
|
||||
|
||||
sleep 2
|
||||
echo "Stale sockets removed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "No specific Docker errors detected in logs"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to remove standalone Docker Compose if it exists
|
||||
remove_standalone_docker_compose() {
|
||||
if command -v docker-compose &>/dev/null; then
|
||||
echo "Standalone docker-compose found. Checking installation method..."
|
||||
|
||||
# Check if docker-compose was installed via package manager
|
||||
if dpkg -l | grep -qw docker-compose 2>/dev/null; then
|
||||
echo "Removing docker-compose installed via package manager..."
|
||||
$SUDO apt-get remove -y docker-compose
|
||||
else
|
||||
echo "Removing standalone docker-compose binary..."
|
||||
$SUDO rm -f $(which docker-compose)
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to clean Docker state and fix permissions
|
||||
clean_docker_state() {
|
||||
echo "Cleaning Docker state and fixing permissions..."
|
||||
|
||||
# Stop Docker first
|
||||
if $SUDO systemctl is-active --quiet docker; then
|
||||
echo "Stopping Docker service..."
|
||||
$SUDO systemctl stop docker
|
||||
sleep 2
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Clean up Docker runtime state
|
||||
if [ -d /var/run/docker ]; then
|
||||
echo "Cleaning Docker runtime state..."
|
||||
$SUDO rm -rf /var/run/docker/*
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Fix containerd state
|
||||
if [ -d /run/containerd ]; then
|
||||
echo "Cleaning containerd state..."
|
||||
$SUDO rm -rf /run/containerd/runc
|
||||
$SUDO rm -rf /run/containerd/io.containerd*
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Clean up any stale container state
|
||||
if [ -d /var/lib/docker/containers ]; then
|
||||
echo "Cleaning container state..."
|
||||
$SUDO find /var/lib/docker/containers -name "*.pid" -delete 2>/dev/null || true
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Fix core Docker directory permissions
|
||||
if [ -d /var/lib/docker ]; then
|
||||
echo "Fixing Docker directory permissions..."
|
||||
$SUDO chown -R root:root /var/lib/docker
|
||||
$SUDO chmod 711 /var/lib/docker
|
||||
|
||||
# Fix specific subdirectories
|
||||
[ -d /var/lib/docker/overlay2 ] && $SUDO chmod 755 /var/lib/docker/overlay2
|
||||
[ -d /var/lib/docker/containers ] && $SUDO chmod 755 /var/lib/docker/containers
|
||||
[ -d /var/lib/docker/image ] && $SUDO chmod 755 /var/lib/docker/image
|
||||
[ -d /var/lib/docker/volumes ] && $SUDO chmod 755 /var/lib/docker/volumes
|
||||
|
||||
# Fix overlay2/l directory which is critical for overlay2 storage
|
||||
if [ -d /var/lib/docker/overlay2/l ]; then
|
||||
$SUDO chmod 700 /var/lib/docker/overlay2/l
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Docker state cleanup complete"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to downgrade Docker to compatible version
|
||||
downgrade_docker() {
|
||||
echo "Setting up Docker repository..."
|
||||
$SUDO apt-get update
|
||||
echo ""
|
||||
|
||||
echo "Installing prerequisites..."
|
||||
$SUDO apt-get install -y \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg \
|
||||
lsb-release
|
||||
echo ""
|
||||
|
||||
# Add Docker's official GPG key
|
||||
echo "Adding Docker's official GPG key..."
|
||||
$SUDO install -m 0755 -d /etc/apt/keyrings
|
||||
$SUDO curl -fsSL https://download.docker.com/linux/${OS}/gpg -o /etc/apt/keyrings/docker.asc
|
||||
$SUDO chmod a+r /etc/apt/keyrings/docker.asc
|
||||
echo ""
|
||||
|
||||
# Set up the stable repository
|
||||
echo "Setting up Docker repository..."
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${OS} \
|
||||
${VERSION_CODENAME} stable" | \
|
||||
$SUDO tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
echo ""
|
||||
|
||||
# Update package index with new repository
|
||||
echo "Updating package lists with Docker repository..."
|
||||
$SUDO apt-get update
|
||||
echo ""
|
||||
|
||||
# Get available versions
|
||||
echo "Available Docker CE versions:"
|
||||
apt-cache madison docker-ce | head -n 5
|
||||
echo ""
|
||||
|
||||
# Hold Docker packages to prevent auto-upgrade
|
||||
echo "Configuring Docker packages to prevent auto-upgrade..."
|
||||
$SUDO apt-mark unhold docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>/dev/null || true
|
||||
echo ""
|
||||
|
||||
# Install specific Docker version compatible with CasaOS
|
||||
echo "Installing Docker version compatible with CasaOS (24.0.7)..."
|
||||
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
DOCKER_CE_FULL="${DOCKER_CE_VERSION}${OS}~${VERSION_CODENAME}"
|
||||
DOCKER_CLI_FULL="${DOCKER_CLI_VERSION}${OS}~${VERSION_CODENAME}"
|
||||
CONTAINERD_FULL="${CONTAINERD_VERSION}~${OS}~${VERSION_CODENAME}"
|
||||
|
||||
# Check if we're in LXC and warn about containerd version
|
||||
if check_lxc_environment; then
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "LXC/Proxmox Environment Detected"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Installing containerd.io ${CONTAINERD_VERSION} to avoid CVE-2025-52881 AppArmor issues."
|
||||
echo "This version is safe and prevents 'permission denied' errors on sysctl."
|
||||
echo ""
|
||||
echo "For more information, see:"
|
||||
echo "https://github.com/opencontainers/runc/issues/4968"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Installing docker-ce-cli=${DOCKER_CLI_FULL}"
|
||||
echo "Installing docker-ce=${DOCKER_CE_FULL}"
|
||||
echo "Installing containerd.io=${CONTAINERD_FULL}"
|
||||
echo ""
|
||||
|
||||
$SUDO apt-get install -y --allow-downgrades \
|
||||
docker-ce-cli=${DOCKER_CLI_FULL} \
|
||||
docker-ce=${DOCKER_CE_FULL} \
|
||||
containerd.io=${CONTAINERD_FULL} \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin || {
|
||||
echo ""
|
||||
echo "Specific version installation failed. Trying alternative method..."
|
||||
echo ""
|
||||
|
||||
# Fallback: try without the full version string but keep containerd specific
|
||||
$SUDO apt-get install -y --allow-downgrades \
|
||||
docker-ce=5:24.0.* \
|
||||
docker-ce-cli=5:24.0.* \
|
||||
containerd.io=${CONTAINERD_FULL} \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin || {
|
||||
# Last resort: try with pattern match for containerd
|
||||
echo ""
|
||||
echo "Trying with containerd.io version pattern..."
|
||||
echo ""
|
||||
$SUDO apt-get install -y --allow-downgrades \
|
||||
docker-ce=5:24.0.* \
|
||||
docker-ce-cli=5:24.0.* \
|
||||
containerd.io=1.7.28-1* \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin
|
||||
}
|
||||
}
|
||||
echo ""
|
||||
|
||||
# Hold packages to prevent auto-upgrade
|
||||
echo "Holding Docker packages at current version..."
|
||||
$SUDO apt-mark hold docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
echo ""
|
||||
|
||||
# Check if daemon.json exists and validate it
|
||||
if [ -f /etc/docker/daemon.json ]; then
|
||||
echo "Existing daemon.json found - preserving user configuration..."
|
||||
if ! validate_daemon_json; then
|
||||
echo "WARNING: Your existing daemon.json may have syntax errors"
|
||||
echo "Please check /etc/docker/daemon.json for any issues"
|
||||
else
|
||||
echo "Existing daemon.json is valid - keeping it unchanged"
|
||||
fi
|
||||
else
|
||||
echo "No daemon.json found - Docker will use default settings"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Fix overlay2 permissions if directory exists
|
||||
if [ -d /var/lib/docker/overlay2 ]; then
|
||||
echo "Fixing overlay2 directory permissions..."
|
||||
$SUDO chown -R root:root /var/lib/docker/overlay2
|
||||
$SUDO chmod -R 755 /var/lib/docker/overlay2
|
||||
if [ -d /var/lib/docker/overlay2/l ]; then
|
||||
$SUDO chmod 700 /var/lib/docker/overlay2/l
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Reload systemd and restart Docker service
|
||||
echo "Reloading systemd daemon..."
|
||||
$SUDO systemctl daemon-reload
|
||||
echo ""
|
||||
|
||||
# Stop docker socket to prevent auto-restart
|
||||
echo "Stopping Docker socket and service..."
|
||||
$SUDO systemctl stop docker.socket 2>/dev/null || true
|
||||
$SUDO systemctl stop docker
|
||||
sleep 2
|
||||
echo ""
|
||||
|
||||
# Start docker socket first, then service
|
||||
echo "Starting Docker socket..."
|
||||
$SUDO systemctl start docker.socket
|
||||
sleep 1
|
||||
echo ""
|
||||
|
||||
echo "Starting Docker service..."
|
||||
$SUDO systemctl start docker
|
||||
sleep 3
|
||||
echo ""
|
||||
|
||||
# Verify Docker is running
|
||||
if ! $SUDO systemctl is-active --quiet docker; then
|
||||
echo "=========================================="
|
||||
echo "ERROR: Docker service failed to start"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Checking Docker status and logs..."
|
||||
$SUDO systemctl status docker --no-pager -l || true
|
||||
echo ""
|
||||
echo "Recent Docker logs:"
|
||||
$SUDO journalctl -u docker --no-pager -n 50 || true
|
||||
echo ""
|
||||
|
||||
# Attempt to detect and fix the error
|
||||
echo "=========================================="
|
||||
echo "Attempting automatic error detection and fix..."
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
if detect_and_fix_docker_errors; then
|
||||
# Try to start Docker again after fix
|
||||
echo ""
|
||||
echo "Reloading systemd and restarting Docker..."
|
||||
$SUDO systemctl daemon-reload
|
||||
$SUDO systemctl stop docker.socket 2>/dev/null || true
|
||||
$SUDO systemctl stop docker 2>/dev/null || true
|
||||
sleep 2
|
||||
$SUDO systemctl start docker.socket
|
||||
sleep 1
|
||||
$SUDO systemctl start docker
|
||||
sleep 3
|
||||
|
||||
if $SUDO systemctl is-active --quiet docker; then
|
||||
echo "✓ Docker started successfully after automatic fix!"
|
||||
echo ""
|
||||
else
|
||||
echo "✗ Docker still failed to start after automatic fix"
|
||||
echo ""
|
||||
echo "Checking for daemon.json syntax errors..."
|
||||
if command -v dockerd &>/dev/null; then
|
||||
$SUDO dockerd --validate 2>&1 || true
|
||||
fi
|
||||
echo ""
|
||||
echo "Please check the error messages above."
|
||||
if [ -f /etc/docker/daemon.json ]; then
|
||||
echo "daemon.json location: /etc/docker/daemon.json"
|
||||
echo "Backups are in: /etc/docker/daemon.json.backup.*"
|
||||
fi
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "Could not automatically detect/fix the error"
|
||||
echo ""
|
||||
if [ -f /etc/docker/daemon.json ]; then
|
||||
echo "daemon.json location: /etc/docker/daemon.json"
|
||||
echo "You may need to manually review this file"
|
||||
fi
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "Docker service started successfully!"
|
||||
echo ""
|
||||
|
||||
# Test Docker functionality
|
||||
echo "Testing Docker functionality..."
|
||||
if $SUDO docker info >/dev/null 2>&1; then
|
||||
echo "Docker is responding correctly!"
|
||||
echo ""
|
||||
|
||||
# Additional test: Try to run a simple container to check for runtime errors
|
||||
echo "Testing container creation..."
|
||||
if $SUDO docker run --rm hello-world >/dev/null 2>&1; then
|
||||
echo "✓ Container test successful - Docker is fully functional"
|
||||
else
|
||||
echo "⚠ Container test failed - attempting to fix runtime issues..."
|
||||
|
||||
# Check for the specific sysctl permission error
|
||||
test_output=$($SUDO docker run --rm hello-world 2>&1 || true)
|
||||
if echo "$test_output" | grep -q "open sysctl.*permission denied"; then
|
||||
echo ""
|
||||
echo "Detected: Container runtime sysctl permission error (CVE-2025-52881)"
|
||||
echo ""
|
||||
|
||||
# Check containerd version
|
||||
local current_containerd=$(check_containerd_version)
|
||||
echo "Current containerd.io version: $current_containerd"
|
||||
|
||||
if [[ "$current_containerd" =~ 1\.7\.(28-2|29) ]] || [[ "$current_containerd" =~ 1\.7\.(3[0-9]) ]]; then
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "ERROR: Problematic containerd.io version detected!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "You have containerd.io $current_containerd which causes this error."
|
||||
echo "This script should have installed version 1.7.28-1."
|
||||
echo ""
|
||||
echo "This is a known issue with newer containerd versions in LXC/Proxmox."
|
||||
echo "See: https://github.com/opencontainers/runc/issues/4968"
|
||||
echo ""
|
||||
echo "To fix manually:"
|
||||
echo " sudo apt-get install -y --allow-downgrades containerd.io=1.7.28-1~${OS}~${VERSION_CODENAME}"
|
||||
echo " sudo apt-mark hold containerd.io"
|
||||
echo " sudo systemctl restart docker"
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "This error can also indicate corrupted Docker storage"
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "RECOMMENDED ACTION: Full Docker Reset"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "This will:"
|
||||
echo " • Remove all containers and images"
|
||||
echo " • Clear all Docker volumes"
|
||||
echo " • Reset Docker to clean state"
|
||||
echo " • Fix all permission issues"
|
||||
echo ""
|
||||
|
||||
# Ask for user confirmation
|
||||
read -p "Do you want to proceed with Docker reset? (yes/no): " -r
|
||||
echo ""
|
||||
|
||||
if [[ $REPLY =~ ^[Yy][Ee][Ss]$ ]] || [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Performing Docker reset..."
|
||||
|
||||
# Stop all Docker services
|
||||
$SUDO systemctl stop docker.socket 2>/dev/null || true
|
||||
$SUDO systemctl stop docker 2>/dev/null || true
|
||||
$SUDO systemctl stop containerd 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
# Backup important data
|
||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
echo "Creating backup at /var/lib/docker.backup.$timestamp ..."
|
||||
$SUDO mv /var/lib/docker /var/lib/docker.backup.$timestamp
|
||||
|
||||
# Recreate Docker directory structure
|
||||
echo "Creating fresh Docker directory structure..."
|
||||
$SUDO mkdir -p /var/lib/docker
|
||||
$SUDO chmod 711 /var/lib/docker
|
||||
|
||||
# Clean all runtime state
|
||||
$SUDO rm -rf /run/containerd/* 2>/dev/null || true
|
||||
$SUDO rm -rf /var/run/docker/* 2>/dev/null || true
|
||||
|
||||
# Restart services
|
||||
echo "Starting Docker services..."
|
||||
$SUDO systemctl start containerd 2>/dev/null || true
|
||||
sleep 2
|
||||
$SUDO systemctl start docker.socket
|
||||
sleep 1
|
||||
$SUDO systemctl start docker
|
||||
sleep 5
|
||||
|
||||
# Test again
|
||||
echo "Testing Docker after reset..."
|
||||
if $SUDO docker run --rm hello-world >/dev/null 2>&1; then
|
||||
echo ""
|
||||
echo "✓ Docker reset successful!"
|
||||
echo "✓ Containers can now run properly"
|
||||
echo ""
|
||||
echo "Your old data is backed up at:"
|
||||
echo " /var/lib/docker.backup.$timestamp"
|
||||
echo ""
|
||||
else
|
||||
echo ""
|
||||
echo "✗ Docker still has issues after reset"
|
||||
echo "Please check the logs with:"
|
||||
echo " sudo journalctl -u docker --no-pager -n 100"
|
||||
fi
|
||||
else
|
||||
echo "Docker reset cancelled."
|
||||
echo ""
|
||||
echo "⚠ WARNING: Your Docker installation has container runtime errors"
|
||||
echo "Containers will not be able to start until this is resolved."
|
||||
echo ""
|
||||
echo "To manually reset later:"
|
||||
echo " sudo systemctl stop docker"
|
||||
echo " sudo mv /var/lib/docker /var/lib/docker.backup"
|
||||
echo " sudo systemctl start docker"
|
||||
fi
|
||||
else
|
||||
echo "⚠ Container test failed for unknown reason"
|
||||
echo "Error output:"
|
||||
echo "$test_output"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Warning: Docker started but may not be fully functional"
|
||||
$SUDO docker info || true
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
echo "Step 1: Checking system..."
|
||||
check_sudo
|
||||
detect_os
|
||||
|
||||
echo "Step 2: Checking for CasaOS..."
|
||||
CASAOS_INSTALLED=false
|
||||
if check_casaos; then
|
||||
CASAOS_INSTALLED=true
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "Step 2a: Checking environment..."
|
||||
if check_lxc_environment; then
|
||||
echo "Running in LXC/Proxmox container - will use containerd.io ${CONTAINERD_VERSION}"
|
||||
echo "This avoids CVE-2025-52881 AppArmor sysctl permission issues."
|
||||
else
|
||||
echo "Running on standard system (not LXC)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "Step 3: Displaying current Docker versions..."
|
||||
display_versions
|
||||
|
||||
echo "Step 4: Stopping CasaOS services (if installed)..."
|
||||
if [ "$CASAOS_INSTALLED" = true ]; then
|
||||
stop_casaos_services
|
||||
else
|
||||
echo "CasaOS not installed, skipping service stop."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Step 5: Removing standalone docker-compose if present..."
|
||||
remove_standalone_docker_compose
|
||||
|
||||
echo "Step 6: Cleaning Docker state and fixing permissions..."
|
||||
clean_docker_state
|
||||
|
||||
echo "Step 7: Installing Docker version compatible with CasaOS..."
|
||||
if ! downgrade_docker; then
|
||||
echo "=========================================="
|
||||
echo "ERROR: Docker installation/configuration failed"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Attempting to start Docker..."
|
||||
|
||||
# Try to start Docker
|
||||
$SUDO systemctl start docker.socket 2>/dev/null || true
|
||||
$SUDO systemctl start docker
|
||||
sleep 3
|
||||
|
||||
if ! $SUDO systemctl is-active --quiet docker; then
|
||||
echo "Could not start Docker. Please check the error messages above."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Docker started with previous configuration."
|
||||
echo "The version downgrade may have failed, but Docker is running."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
echo "Docker Configuration Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Current Docker versions:"
|
||||
docker version 2>&1 || echo "Unable to get Docker version"
|
||||
echo ""
|
||||
if command -v docker &>/dev/null; then
|
||||
docker compose version 2>&1 || echo "Unable to get Docker Compose version"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [ "$CASAOS_INSTALLED" = true ]; then
|
||||
echo "Step 8: Restarting CasaOS services..."
|
||||
start_casaos_services
|
||||
|
||||
echo "=========================================="
|
||||
echo "CasaOS Docker Fix Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Docker has been set to version 24.0.7 (compatible with CasaOS)"
|
||||
echo "Docker packages have been held to prevent automatic upgrades."
|
||||
echo ""
|
||||
echo "To allow Docker to be upgraded in the future, run:"
|
||||
echo " sudo apt-mark unhold docker-ce docker-ce-cli containerd.io"
|
||||
echo ""
|
||||
echo "If you found this helpful, please consider supporting BigBear:"
|
||||
echo " https://ko-fi.com/bigbeartechworld"
|
||||
echo ""
|
||||
else
|
||||
echo "=========================================="
|
||||
echo "Docker version has been set to 24.0.7"
|
||||
echo "This version is compatible with CasaOS API 1.43"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "The Docker client version error should now be resolved."
|
||||
echo "You can now run your Docker commands without API version issues."
|
||||
}
|
||||
|
||||
# Execute the main function
|
||||
main
|
||||
Reference in New Issue
Block a user