#!/usr/bin/env bash # Setup a fresh Linux server as Docker host with Portainer and Nginx Proxy Manager. # Run over SSH: copy script to server, then: chmod +x docker-host-setup.sh && sudo ./docker-host-setup.sh # # Optional env (set before running): # DOCKER_DATA_ROOT - e.g. /mnt/data/docker (default: leave Docker's default) # VOL_BASE - volume base for portainer and proxy (default: /opt/docker-vol) # usage: sudo DOCKER_DATA_ROOT=/mnt/data/docker VOL_BASE=/mnt/data/docker-vol ./docker-host-setup.sh set -e VOL_BASE="${VOL_BASE:-/opt/docker-vol}" DOCKER_DATA_ROOT="${DOCKER_DATA_ROOT:-}" # --- 1. Detect OS and install Docker --- if ! command -v docker &>/dev/null; then if [ -f /etc/os-release ]; then . /etc/os-release else echo "Cannot detect OS. Install Docker manually and re-run for Portainer/NPM only." exit 1 fi if [[ "$ID" != "ubuntu" && "$ID" != "debian" ]]; then echo "This script supports Ubuntu/Debian. For other distros install Docker and re-run." exit 1 fi echo "Installing Docker (Ubuntu/Debian)..." apt-get update -qq apt-get install -y -qq ca-certificates curl gnupg install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/"$ID"/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$ID $VERSION_CODENAME stable" \ > /etc/apt/sources.list.d/docker.list apt-get update -qq apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin fi # --- 2. Optional custom Docker data root --- if [ -n "$DOCKER_DATA_ROOT" ]; then echo "Setting Docker data-root to $DOCKER_DATA_ROOT" mkdir -p "$DOCKER_DATA_ROOT" if [ -f /etc/docker/daemon.json ] && grep -q '"data-root"' /etc/docker/daemon.json; then echo "Docker daemon.json already has data-root, skipping." else if [ -f /etc/docker/daemon.json ]; then if command -v python3 &>/dev/null; then python3 -c " import json, sys p = '/etc/docker/daemon.json' with open(p) as f: d = json.load(f) d['data-root'] = sys.argv[1] with open(p, 'w') as f: json.dump(d, f, indent=2) " "$DOCKER_DATA_ROOT" else echo "Add manually to /etc/docker/daemon.json: \"data-root\": \"$DOCKER_DATA_ROOT\"" fi else printf '%s\n' "{\"data-root\": \"$DOCKER_DATA_ROOT\"}" > /etc/docker/daemon.json fi fi systemctl restart docker sleep 2 fi systemctl enable docker systemctl start docker # Add current user to docker group so they can run docker without sudo if [ -n "${SUDO_USER:-}" ]; then usermod -aG docker "$SUDO_USER" echo "Added $SUDO_USER to group docker. Log out and back in (or newgrp docker) for it to take effect." fi # --- 3. Volume dirs for Portainer and Nginx Proxy Manager --- mkdir -p "$VOL_BASE/portainer" "$VOL_BASE/proxy/data" "$VOL_BASE/proxy/letsencrypt" echo "Volume base: $VOL_BASE" # --- 4. Start Portainer --- if ! docker ps -a --format '{{.Names}}' | grep -qx portainer; then echo "Starting Portainer..." docker run -d \ -p 8000:8000 -p 9000:9000 \ --name portainer --restart always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$VOL_BASE/portainer:/data" \ portainer/portainer-ce:latest echo "Portainer: http://:9000 (set admin password on first visit)" else echo "Portainer container already exists. Start with: docker start portainer" fi # --- 5. Start Nginx Proxy Manager --- if ! docker ps -a --format '{{.Names}}' | grep -qx proxy; then echo "Starting Nginx Proxy Manager..." docker run -d \ --name proxy --restart always \ -p 80:80 -p 443:443 -p 81:81 \ -e PUID=0 -e PGID=0 \ -v "$VOL_BASE/proxy/data:/data" \ -v "$VOL_BASE/proxy/letsencrypt:/etc/letsencrypt" \ jc21/nginx-proxy-manager:latest echo "NPM admin: http://:81 (default login: admin@example.com / changeme)" else echo "Nginx Proxy Manager container already exists. Start with: docker start proxy" fi echo "" echo "Done. Portainer: :9000 NPM admin: :81 NPM HTTP/HTTPS: :80 :443" echo "Change NPM default password and Portainer admin password after first login."