| #!/bin/bash |
| set -euo pipefail |
|
|
| |
| INSTALL_BASE="${HOME}/workspace" |
| COMFYUI_ROOT="${INSTALL_BASE}/comfyui" |
| COMFYUI_DIR="${INSTALL_BASE}/comfyui/ComfyUI" |
| COMFY_PORT=8188 |
|
|
| LOGFILE="/tmp/cloudflared_8188.log" |
| HELPERS_LOGFILE="/tmp/helpers.log" |
| SETUP_LOG="/tmp/gcp_comfysetup_setup.log" |
| COMFYUI_LOG="/tmp/comfyui.log" |
| |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
|
|
| |
| if [ -t 1 ]; then |
| RESET=$'\033[0m' |
| BOLD=$'\033[1m' |
| RED=$'\033[31m' |
| GREEN=$'\033[32m' |
| YELLOW=$'\033[33m' |
| BLUE=$'\033[34m' |
| CYAN=$'\033[36m' |
| else |
| RESET="" |
| BOLD="" |
| RED="" |
| GREEN="" |
| YELLOW="" |
| BLUE="" |
| CYAN="" |
| fi |
|
|
| : > "${SETUP_LOG}" |
| : > "${COMFYUI_LOG}" |
|
|
| log() { printf "%b[%s]%b %s\n" "${BLUE}" "INFO" "${RESET}" "$1"; } |
| err() { printf "%b[%s]%b %s\n" "${RED}" "ERROR" "${RESET}" "$1" >&2; exit 1; } |
| ok() { printf "%b[%s]%b %s\n" "${GREEN}" "OK" "${RESET}" "$1"; } |
| section() { printf "\n%b%s%b\n" "${BOLD}${CYAN}" "$1" "${RESET}"; } |
| kv() { printf " %b%-22s%b %s\n" "${YELLOW}" "$1" "${RESET}" "$2"; } |
|
|
| run_logged() { |
| local label="$1" |
| local logfile="$2" |
| shift 2 |
|
|
| printf " %b[%s]%b %s\n" "${BLUE}" ".." "${RESET}" "$label" |
| if "$@" >>"${logfile}" 2>&1; then |
| printf " %b[%s]%b %s\n" "${GREEN}" "OK" "${RESET}" "$label" |
| else |
| printf " %b[%s]%b %s\n" "${RED}" "FAIL" "${RESET}" "$label" >&2 |
| printf "%s\n" "--- last 40 lines from ${logfile} ---" >&2 |
| tail -n 40 "${logfile}" >&2 || true |
| exit 1 |
| fi |
| } |
|
|
| get_cloudflare_url() { |
| local timeout="${1:-60}" |
| local waited=0 |
|
|
| while [ "$waited" -lt "$timeout" ]; do |
| if [ -f "${LOGFILE}" ]; then |
| local url |
| url=$(grep -oE 'https://[a-zA-Z0-9.-]+\.trycloudflare\.com' "${LOGFILE}" | head -n 1 || true) |
| if [ -n "$url" ]; then |
| echo "$url" |
| return 0 |
| fi |
| fi |
|
|
| sleep 1 |
| waited=$((waited + 1)) |
| done |
|
|
| return 1 |
| } |
|
|
| get_gradio_url() { |
| local timeout="${1:-60}" |
| local waited=0 |
|
|
| while [ "$waited" -lt "$timeout" ]; do |
| if [ -f "${HELPERS_LOGFILE}" ]; then |
| local url |
| url=$(grep -oE 'https://[a-zA-Z0-9.-]+\.gradio\.live' "${HELPERS_LOGFILE}" | head -n 1 || true) |
| if [ -n "$url" ]; then |
| echo "$url" |
| return 0 |
| fi |
| fi |
|
|
| sleep 1 |
| waited=$((waited + 1)) |
| done |
|
|
| return 1 |
| } |
|
|
| |
| section "1. Preparing GCP Workspace Directory" |
| mkdir -p "${INSTALL_BASE}" |
| ok "Workspace directory ready: ${INSTALL_BASE}" |
|
|
| section "gcp_comfysetup Dashboard" |
| kv "Install base" "${INSTALL_BASE}" |
| kv "ComfyUI root" "${COMFYUI_ROOT}" |
| kv "ComfyUI Dir" "${COMFYUI_DIR}" |
| kv "Port" "${COMFY_PORT}" |
| kv "Log file" "${SETUP_LOG}" |
| kv "ComfyUI Log" "${COMFYUI_LOG}" |
|
|
| |
| section "2. Installing System Dependencies & Tools" |
|
|
| SUDO_CMD="" |
| if command -v sudo >/dev/null 2>&1; then |
| SUDO_CMD="sudo" |
| fi |
|
|
| run_logged "apt update" "${SETUP_LOG}" ${SUDO_CMD} apt-get update -y || apt-get update -y |
| run_logged "apt install core tools" "${SETUP_LOG}" ${SUDO_CMD} apt-get install -y \ |
| curl git screen python3 python3-venv lsb-release \ |
| zip aria2 nano build-essential ffmpeg || apt-get install -y \ |
| curl git screen python3 python3-venv lsb-release \ |
| zip aria2 nano build-essential ffmpeg |
|
|
| |
| if ! command -v uv >/dev/null 2>&1; then |
| run_logged "install uv" "${SETUP_LOG}" bash -lc 'curl -Ls https://astral.sh/uv/install.sh | sh' |
| fi |
|
|
| export PATH="${HOME}/.local/bin:${HOME}/.cargo/bin:/root/.cargo/bin:$PATH" |
| if [ -f "${HOME}/.local/bin/env" ]; then |
| source "${HOME}/.local/bin/env" || true |
| fi |
|
|
| |
| if ! command -v cloudflared >/dev/null 2>&1; then |
| run_logged "download cloudflare key" "${SETUP_LOG}" ${SUDO_CMD} curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg -o /usr/share/keyrings/cloudflare-archive-keyring.gpg || curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg -o /usr/share/keyrings/cloudflare-archive-keyring.gpg |
| |
| ${SUDO_CMD} bash -c "printf 'deb [signed-by=/usr/share/keyrings/cloudflare-archive-keyring.gpg] https://pkg.cloudflare.com/cloudflared/ %s main\n' \"\$(lsb_release -cs)\" > /etc/apt/sources.list.d/cloudflared.list" || true |
| |
| run_logged "apt update cloudflared" "${SETUP_LOG}" ${SUDO_CMD} apt-get update -y || apt-get update -y |
| run_logged "apt install cloudflared" "${SETUP_LOG}" ${SUDO_CMD} apt-get install -y cloudflared || apt-get install -y cloudflared |
| fi |
|
|
| |
| if ! command -v rclone >/dev/null 2>&1; then |
| run_logged "install rclone" "${SETUP_LOG}" bash -c "curl -fsSL https://rclone.org/install.sh | ${SUDO_CMD} bash" |
| fi |
|
|
| ok "System dependencies & tools installed" |
|
|
| |
| section "3. Setting up ComfyUI Screen Session & Dependencies" |
|
|
| screen -dmS comfyui bash -lc " |
| ( |
| set -euo pipefail |
| |
| mkdir -p ${COMFYUI_ROOT} |
| cd ${COMFYUI_ROOT} |
| |
| if [ ! -d ComfyUI ]; then |
| git clone --depth 1 https://github.com/comfyanonymous/ComfyUI |
| fi |
| |
| cd ComfyUI |
| git reset --hard || true |
| git clean -fd || true |
| git pull --force || true |
| |
| # ---- Python Virtual Environment ---- |
| if [ ! -d venv ]; then |
| python3 -m venv venv |
| fi |
| source venv/bin/activate |
| |
| # Upgrade pip |
| pip install --upgrade pip |
| |
| # Determine installer (uv if available, else pip) |
| INSTALLER=\"pip install\" |
| if command -v uv >/dev/null 2>&1; then |
| INSTALLER=\"uv pip install\" |
| elif [ -f \"\${HOME}/.local/bin/uv\" ]; then |
| INSTALLER=\"\${HOME}/.local/bin/uv pip install\" |
| fi |
| |
| # ---- Install PyTorch 2.11.0 (CUDA 12.8) ---- |
| echo '=== Installing PyTorch 2.11.0 (CUDA 12.8) ===' |
| \${INSTALLER} torch==2.11.0 torchvision==0.26.0 torchaudio==2.11.0 --index-url https://download.pytorch.org/whl/cu128 |
| |
| # ---- Install xFormers ---- |
| echo '=== Installing xFormers ===' |
| \${INSTALLER} xformers --no-deps || \${INSTALLER} xformers || true |
| |
| # ---- Install Custom Nodes ---- |
| mkdir -p custom_nodes |
| cd custom_nodes |
| |
| repos=( |
| https://github.com/ltdrdata/ComfyUI-Manager |
| https://github.com/city96/ComfyUI-GGUF |
| https://github.com/ClownsharkBatwing/RES4LYF |
| https://github.com/rgthree/rgthree-comfy |
| https://github.com/crystian/ComfyUI-Crystools |
| https://github.com/MoonGoblinDev/Civicomfy |
| https://github.com/1038lab/ComfyUI-QwenVL |
| https://github.com/1038lab/ComfyUI-RMBG |
| https://github.com/Fannovel16/ComfyUI-Frame-Interpolation |
| https://github.com/kijai/ComfyUI-KJNodes |
| https://github.com/liusida/ComfyUI-Login |
| https://github.com/numz/ComfyUI-SeedVR2_VideoUpscaler |
| https://github.com/LAOGOU-666/Comfyui-Memory_Cleanup |
| ) |
| |
| rm -f /tmp/merged_reqs.txt |
| |
| for repo in \"\${repos[@]}\"; do |
| name=\$(basename \"\$repo\" .git) |
| [ -d \"\$name\" ] || git clone --depth 1 \"\$repo\" |
| cd \"\$name\" || continue |
| git pull --force || true |
| [ -f requirements.txt ] && echo \"\" >> /tmp/merged_reqs.txt && cat requirements.txt >> /tmp/merged_reqs.txt |
| cd .. |
| done |
| |
| cd .. |
| [ -f requirements.txt ] && echo \"\" >> /tmp/merged_reqs.txt && cat requirements.txt >> /tmp/merged_reqs.txt |
| [ -f /tmp/merged_reqs.txt ] && \${INSTALLER} -r /tmp/merged_reqs.txt --extra-index-url https://download.pytorch.org/whl/cu128 || true |
| rm -f /tmp/merged_reqs.txt |
| |
| # ---- Extra Dependencies ---- |
| \${INSTALLER} insightface || true |
| |
| # ---- Launch ComfyUI ---- |
| echo '=== Launching ComfyUI Server ===' |
| exec python main.py \ |
| --listen 0.0.0.0 \ |
| --port ${COMFY_PORT} |
| ) 2>&1 | tee ${COMFYUI_LOG} |
| exec bash |
| " |
|
|
| log "ComfyUI screen session launched (screen -r comfyui)" |
|
|
| |
| section "4. Starting Cloudflared Tunnel" |
|
|
| rm -f "${LOGFILE}" |
|
|
| screen -dmS tunnel8188 bash -lc " |
| cloudflared tunnel \ |
| --no-autoupdate \ |
| --url http://127.0.0.1:${COMFY_PORT} \ |
| > ${LOGFILE} 2>&1 |
| exec bash |
| " |
|
|
| log "Cloudflared launched (screen -r tunnel8188)" |
| log "Waiting for Cloudflared public URL..." |
| CLOUDFLARE_URL="$(get_cloudflare_url 60 || true)" |
|
|
| |
| section "5. Starting Helper Tools UI" |
|
|
| rm -f "${HELPERS_LOGFILE}" |
| HELPERS_DIR="${INSTALL_BASE}/helpers" |
| mkdir -p "${HELPERS_DIR}" |
|
|
| if [ -f "${SCRIPT_DIR}/helpers.py" ]; then |
| cp "${SCRIPT_DIR}/helpers.py" "${HELPERS_DIR}/helpers.py" |
| else |
| curl -fsSL -o "${HELPERS_DIR}/helpers.py" https://huggingface.co/gtaayush010/gcp_comfysetup/resolve/main/helpers.py |
| fi |
|
|
| screen -dmS helpers bash -lc " |
| set -euo pipefail |
| |
| cd ${HELPERS_DIR} |
| export PATH=\"\${HOME}/.local/bin:\${HOME}/.cargo/bin:\$PATH\" |
| |
| if [ ! -d venv ]; then |
| python3 -m venv venv |
| fi |
| source venv/bin/activate |
| |
| if command -v uv >/dev/null 2>&1; then |
| uv pip install gradio huggingface_hub |
| else |
| pip install --upgrade pip |
| pip install gradio huggingface_hub |
| fi |
| |
| export PYTHONUNBUFFERED=1 |
| python helpers.py 2>&1 | tee ${HELPERS_LOGFILE} || true |
| exec bash |
| " |
|
|
| log "Helpers UI launched (screen -r helpers)" |
|
|
| |
| section "6. Generating Reboot Recovery Script" |
|
|
| RESTART_SCRIPT="${INSTALL_BASE}/restart_after_reboot.sh" |
|
|
| cat <<'EOF' > "${RESTART_SCRIPT}" |
| |
| set -euo pipefail |
|
|
| INSTALL_BASE="${HOME}/workspace" |
| COMFYUI_ROOT="${INSTALL_BASE}/comfyui" |
| COMFYUI_DIR="${COMFYUI_ROOT}/ComfyUI" |
| COMFY_PORT=8188 |
| LOGFILE="/tmp/cloudflared_8188.log" |
| HELPERS_LOGFILE="/tmp/helpers.log" |
|
|
| export PATH="${HOME}/.local/bin:${HOME}/.cargo/bin:$PATH" |
|
|
| echo "=== Restarting ComfyUI Services on GCP ===" |
|
|
| |
| if ! screen -list | grep -q "comfyui"; then |
| echo "Launching ComfyUI screen..." |
| screen -dmS comfyui bash -lc " |
| cd ${COMFYUI_DIR} |
| source venv/bin/activate |
| exec python main.py --listen 0.0.0.0 --port ${COMFY_PORT} |
| " |
| else |
| echo "ComfyUI screen session is already running." |
| fi |
|
|
| |
| if ! screen -list | grep -q "tunnel8188"; then |
| echo "Launching Cloudflared tunnel screen..." |
| rm -f ${LOGFILE} |
| screen -dmS tunnel8188 bash -lc " |
| cloudflared tunnel --no-autoupdate --url http://127.0.0.1:${COMFY_PORT} > ${LOGFILE} 2>&1 |
| exec bash |
| " |
| else |
| echo "Cloudflared screen session is already running." |
| fi |
|
|
| |
| if ! screen -list | grep -q "helpers"; then |
| echo "Launching Helpers screen..." |
| rm -f ${HELPERS_LOGFILE} |
| screen -dmS helpers bash -lc " |
| cd ${INSTALL_BASE}/helpers |
| source venv/bin/activate |
| export PYTHONUNBUFFERED=1 |
| python helpers.py 2>&1 | tee ${HELPERS_LOGFILE} || true |
| exec bash |
| " |
| else |
| echo "Helpers screen session is already running." |
| fi |
|
|
| echo "=== All services restarted successfully ===" |
| EOF |
|
|
| chmod +x "${RESTART_SCRIPT}" |
| ok "Reboot recovery script created: ${RESTART_SCRIPT}" |
|
|
| |
| section "Setup Complete!" |
| kv "Installation Path" "${INSTALL_BASE}" |
| kv "ComfyUI Directory" "${COMFYUI_DIR}" |
| kv "PyTorch Version" "2.11.0 + xFormers (CUDA 12.8)" |
| if [ -n "${CLOUDFLARE_URL}" ]; then |
| kv "Cloudflare URL" "${CLOUDFLARE_URL}" |
| else |
| kv "Cloudflare URL" "Initializing... (check screen -r tunnel8188)" |
| fi |
|
|
| section "Screen Attach Commands" |
| kv "ComfyUI" "screen -r comfyui" |
| kv "Tunnel" "screen -r tunnel8188" |
| kv "Helpers" "screen -r helpers" |
|
|
| section "GCP Reboot Recovery" |
| kv "Restart Command" "bash ${RESTART_SCRIPT}" |
|
|
| section "Waiting for Gradio Helper URL..." |
| GRADIO_URL="$(get_gradio_url 3600 || true)" |
|
|
| if [ -n "${GRADIO_URL}" ]; then |
| section "Gradio Helper UI" |
| kv "Public URL" "${GRADIO_URL}" |
| else |
| section "Gradio Helper UI" |
| kv "Status" "Timed out waiting or check screen -r helpers" |
| fi |
|
|
| ok "All setup operations completed successfully!" |
|
|