mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Make ports 80 and 443 compatible with UFW
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
{
|
||||
servers {
|
||||
listener_wrappers {
|
||||
proxy_protocol
|
||||
tls
|
||||
}
|
||||
|
||||
# Only trust PROXY protocol from local forwarder.
|
||||
trusted_proxies static 127.0.0.1/32 ::1/128
|
||||
}
|
||||
|
||||
http_port 8080
|
||||
https_port 8443
|
||||
}
|
||||
|
||||
fromchat.ru {
|
||||
reverse_proxy frontend:8301 {
|
||||
header_up X-Real-IP {remote_host}
|
||||
@@ -103,11 +118,3 @@ git.fromchat.ru {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api.getgadgets.toolbox-io.ru {
|
||||
reverse_proxy 95.165.0.162:8400
|
||||
}
|
||||
|
||||
getgadgets.toolbox-io.ru {
|
||||
reverse_proxy 95.165.0.162:8401
|
||||
}
|
||||
@@ -167,8 +167,8 @@ services:
|
||||
- production
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "127.0.0.1:8080:8080"
|
||||
- "127.0.0.1:8443:8443"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
@@ -179,6 +179,22 @@ services:
|
||||
networks:
|
||||
- public
|
||||
|
||||
haproxy:
|
||||
image: haproxy:latest
|
||||
profiles:
|
||||
- production
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
# Image defaults to USER haproxy (non-root); that user cannot bind 80/443 on host.
|
||||
# Rootful Docker does not change that — only the container user does.
|
||||
user: "0:0"
|
||||
cap_add:
|
||||
- NET_BIND_SERVICE
|
||||
depends_on:
|
||||
- caddy
|
||||
volumes:
|
||||
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
|
||||
|
||||
postgres:
|
||||
build:
|
||||
context: .
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
global
|
||||
maxconn 4096
|
||||
# Start as root to bind 80/443, then drop privileges.
|
||||
user haproxy
|
||||
group haproxy
|
||||
|
||||
defaults
|
||||
no log
|
||||
mode tcp
|
||||
timeout connect 5s
|
||||
timeout client 2m
|
||||
timeout server 2m
|
||||
|
||||
frontend fe_http_80
|
||||
bind 0.0.0.0:80
|
||||
default_backend be_caddy_http
|
||||
|
||||
backend be_caddy_http
|
||||
server caddy_http 127.0.0.1:8080 send-proxy-v2
|
||||
|
||||
frontend fe_https_443
|
||||
bind 0.0.0.0:443
|
||||
default_backend be_caddy_https
|
||||
|
||||
backend be_caddy_https
|
||||
server caddy_https 127.0.0.1:8443 send-proxy-v2
|
||||
+489
-80
@@ -31,25 +31,19 @@ substep() {
|
||||
|
||||
echo -e "${MAGENTA}${BOLD}🚀 Deployment${NC}\n"
|
||||
|
||||
# Read password with asterisks
|
||||
|
||||
read_password() {
|
||||
local password=""
|
||||
local char
|
||||
local old_stty
|
||||
|
||||
# Save current terminal settings
|
||||
old_stty=$(stty -g 2>/dev/null)
|
||||
|
||||
# Disable echo
|
||||
stty -echo 2>/dev/null
|
||||
|
||||
# Read characters one by one
|
||||
while IFS= read -rs -n 1 char; do
|
||||
# Check for Enter key (empty means Enter was pressed)
|
||||
if [ -z "$char" ]; then
|
||||
break
|
||||
fi
|
||||
# Check for backspace/delete (ASCII 127)
|
||||
if [ "$char" = $'\177' ] || [ "$char" = $'\b' ]; then
|
||||
if [ ${#password} -gt 0 ]; then
|
||||
password="${password%?}"
|
||||
@@ -61,7 +55,6 @@ read_password() {
|
||||
fi
|
||||
done
|
||||
|
||||
# Restore terminal settings
|
||||
stty "$old_stty" 2>/dev/null
|
||||
echo "" >&2
|
||||
echo "$password"
|
||||
@@ -95,6 +88,20 @@ REPO_NAME="FromChat"
|
||||
DEPLOY_PATH="~/actions-runner/_work/$REPO_NAME/$REPO_NAME"
|
||||
PLATFORM="linux/arm64"
|
||||
|
||||
# Prefer plain `docker build` when target arch matches host arch.
|
||||
# This avoids Docker Desktop buildx export/load issues and is faster for same-arch builds.
|
||||
HOST_ARCH_RAW="$(uname -m 2>/dev/null || echo "")"
|
||||
case "$HOST_ARCH_RAW" in
|
||||
arm64|aarch64) HOST_ARCH="arm64" ;;
|
||||
x86_64|amd64) HOST_ARCH="amd64" ;;
|
||||
*) HOST_ARCH="$HOST_ARCH_RAW" ;;
|
||||
esac
|
||||
PLATFORM_ARCH="${PLATFORM##*/}"
|
||||
USE_DOCKER_BUILD=false
|
||||
if [ -n "$HOST_ARCH" ] && [ "$HOST_ARCH" = "$PLATFORM_ARCH" ]; then
|
||||
USE_DOCKER_BUILD=true
|
||||
fi
|
||||
|
||||
# Check if server is provided
|
||||
if [ -z "$SERVER" ]; then
|
||||
error "Server not specified. Usage: $0 [user@host] [deployment_path] [platform]"
|
||||
@@ -146,48 +153,15 @@ if [ "$KEY_LOADED" = false ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if SSH key authentication already works
|
||||
if ssh -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$SERVER" "echo 'SSH key works'" >/dev/null 2>&1; then
|
||||
# SSH key already works, no need to copy
|
||||
true
|
||||
else
|
||||
# Check if our public key is already on the server
|
||||
KEY_CONTENT=$(cat "$SSH_KEY_PUB_FILE")
|
||||
if ssh -o BatchMode=no -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$SERVER" "
|
||||
grep -q '$KEY_CONTENT' ~/.ssh/authorized_keys 2>/dev/null
|
||||
" >/dev/null 2>&1; then
|
||||
# Key exists but authentication failed - might be permissions issue
|
||||
error "SSH key found on server but authentication failed. Check server SSH configuration."
|
||||
# Require key-based SSH auth; do not attempt to copy keys automatically.
|
||||
if ! ssh -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$SERVER" "echo 'SSH key works'" >/dev/null 2>&1; then
|
||||
error "SSH key authentication failed for $SERVER"
|
||||
echo " Copy your public key to the server, then re-run deploy:"
|
||||
echo " ssh-copy-id -i \"$SSH_KEY_PUB_FILE\" \"$SERVER\""
|
||||
echo ""
|
||||
echo " Or manually append this key to ~/.ssh/authorized_keys on the server:"
|
||||
echo " $(cat "$SSH_KEY_PUB_FILE")"
|
||||
exit 1
|
||||
else
|
||||
# Key not on server, need to copy it
|
||||
substep "SSH password: " -n
|
||||
SSH_PASSWORD=$(read_password)
|
||||
|
||||
if [ -z "$SSH_PASSWORD" ]; then
|
||||
error "No SSH password provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
substep "Copying SSH key to server..."
|
||||
if command -v expect >/dev/null 2>&1; then
|
||||
expect << EOF >/dev/null 2>&1
|
||||
spawn ssh-copy-id -o ConnectTimeout=10 -o StrictHostKeyChecking=no -i "$SSH_KEY_PUB_FILE" "$SERVER"
|
||||
expect "password:"
|
||||
send "$SSH_PASSWORD\r"
|
||||
expect eof
|
||||
EOF
|
||||
if [ $? -eq 0 ]; then
|
||||
true
|
||||
else
|
||||
error "Failed to copy SSH key to server"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
error "expect not available - cannot copy SSH key"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
@@ -195,15 +169,7 @@ fi
|
||||
# ============================================================================
|
||||
|
||||
SUDO_PASSWORD=""
|
||||
# If SSH password was provided, try using it for sudo first
|
||||
if [ -n "$SSH_PASSWORD" ]; then
|
||||
if echo "$SSH_PASSWORD" | ssh "$SERVER" "sudo -S -v" > /dev/null 2>&1; then
|
||||
SUDO_PASSWORD="$SSH_PASSWORD"
|
||||
export SUDO_PASSWORD
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we don't have a working sudo password yet, prompt for it
|
||||
# Prompt for sudo password (optional; leave blank for passwordless sudo)
|
||||
if [ -z "$SUDO_PASSWORD" ]; then
|
||||
while true; do
|
||||
substep "Sudo password: " -n
|
||||
@@ -266,11 +232,6 @@ start_docker_desktop() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check buildx
|
||||
if ! docker buildx version > /dev/null 2>&1; then
|
||||
error "Docker buildx not available. Install Docker Desktop."
|
||||
fi
|
||||
|
||||
# Check Docker daemon
|
||||
if ! check_docker_daemon; then
|
||||
warning "Docker daemon is not running"
|
||||
@@ -279,6 +240,12 @@ if ! check_docker_daemon; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
# Check buildx
|
||||
if ! docker buildx version > /dev/null 2>&1; then
|
||||
error "Docker buildx not available. Install Docker Desktop."
|
||||
fi
|
||||
|
||||
# Setup buildx builder
|
||||
step "Setting up buildx builder"
|
||||
BUILDER_NAME="fromchat-builder"
|
||||
@@ -308,6 +275,7 @@ if [ "$BUILDER_EXISTS" = false ]; then
|
||||
fi
|
||||
|
||||
docker buildx use "$BUILDER_NAME" > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Detect services
|
||||
step "Detecting services"
|
||||
@@ -378,7 +346,25 @@ for SERVICE in $SERVICES; do
|
||||
fi
|
||||
fi
|
||||
|
||||
BUILDX_ARGS=(buildx build --platform "$PLATFORM" --file "$DOCKERFILE" --tag "$IMAGE_TAG" --load)
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
DOCKER_BUILD_ARGS=(build --platform "$PLATFORM" --file "$DOCKERFILE" --tag "$IMAGE_TAG")
|
||||
if [ -n "$BUILD_TARGET" ]; then
|
||||
DOCKER_BUILD_ARGS+=(--target "$BUILD_TARGET")
|
||||
fi
|
||||
DOCKER_BUILD_ARGS+=("$BUILD_CONTEXT")
|
||||
|
||||
if docker "${DOCKER_BUILD_ARGS[@]}"; then
|
||||
echo -e " ${GREEN}✓${NC} Built ${CYAN}$SERVICE${NC}"
|
||||
BUILT_IMAGES+=("$IMAGE_TAG")
|
||||
echo ""
|
||||
else
|
||||
error "Build failed for $SERVICE"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# On macOS Docker Desktop, --load can hang for a long time at "sending tarball".
|
||||
# Use the docker exporter explicitly to load into the local Docker daemon.
|
||||
BUILDX_ARGS=(buildx build --platform "$PLATFORM" --file "$DOCKERFILE" --tag "$IMAGE_TAG" --output=type=docker)
|
||||
if [ -n "$BUILD_TARGET" ]; then
|
||||
BUILDX_ARGS+=(--target "$BUILD_TARGET")
|
||||
fi
|
||||
@@ -392,6 +378,407 @@ for SERVICE in $SERVICES; do
|
||||
error "Build failed for $SERVICE"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
true
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||
true
|
||||
fi
|
||||
|
||||
true
|
||||
done
|
||||
|
||||
success "Build complete! ${#BUILT_IMAGES[@]} image(s) ready"
|
||||
@@ -412,26 +799,37 @@ fi
|
||||
# Detect images based on docker-compose.yml (prefer explicit `image:` entries; fall back to built tags)
|
||||
cd "$DEPLOYMENT_DIR"
|
||||
COMPOSE_SERVICES=$(docker compose -f docker-compose.yml config --services 2>/dev/null || true)
|
||||
IMAGES=()
|
||||
PUSH_IMAGES=()
|
||||
EXTERNAL_IMAGES=()
|
||||
|
||||
for S in $COMPOSE_SERVICES; do
|
||||
IMAGE_FROM_COMPOSE=$(jq -r --arg s "$S" '.services[$s].image // empty' <<< "$COMPOSE_JSON")
|
||||
HAS_BUILD=$(jq -r --arg s "$S" '(.services[$s].build // empty) | (if . == "" then "" else "yes" end)' <<< "$COMPOSE_JSON")
|
||||
|
||||
if [ -n "$IMAGE_FROM_COMPOSE" ]; then
|
||||
IMAGES+=("$IMAGE_FROM_COMPOSE")
|
||||
# If it has an explicit image and no build section, it likely won't exist locally (and doesn't need pussh).
|
||||
if [ -z "$HAS_BUILD" ]; then
|
||||
EXTERNAL_IMAGES+=("$IMAGE_FROM_COMPOSE")
|
||||
else
|
||||
# If a service has both build+image, treat it as a built image (pussh).
|
||||
PUSH_IMAGES+=("$IMAGE_FROM_COMPOSE")
|
||||
fi
|
||||
else
|
||||
# If service has a build section (we built it above), use the tag pattern used during build
|
||||
TAG="${PROJECT_NAME}-${S}:latest"
|
||||
# Only include the tag if the image exists locally (avoid pushing unrelated images)
|
||||
if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "^${TAG}$"; then
|
||||
IMAGES+=("$TAG")
|
||||
PUSH_IMAGES+=("$TAG")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Deduplicate while preserving order
|
||||
if [ ${#IMAGES[@]} -gt 0 ]; then
|
||||
IMAGES=($(printf "%s\n" "${IMAGES[@]}" | awk '!seen[$0]++'))
|
||||
if [ ${#PUSH_IMAGES[@]} -gt 0 ]; then
|
||||
PUSH_IMAGES=($(printf "%s\n" "${PUSH_IMAGES[@]}" | awk '!seen[$0]++'))
|
||||
fi
|
||||
if [ ${#EXTERNAL_IMAGES[@]} -gt 0 ]; then
|
||||
EXTERNAL_IMAGES=($(printf "%s\n" "${EXTERNAL_IMAGES[@]}" | awk '!seen[$0]++'))
|
||||
fi
|
||||
|
||||
# Verify that all built images are among the detected images to be pushed.
|
||||
@@ -441,7 +839,7 @@ MATCHING_BUILT=0
|
||||
MISSING_FROM_DETECTED=()
|
||||
for BI in "${BUILT_IMAGES[@]}"; do
|
||||
found=false
|
||||
for DI in "${IMAGES[@]}"; do
|
||||
for DI in "${PUSH_IMAGES[@]}"; do
|
||||
if [ "$BI" = "$DI" ]; then
|
||||
found=true
|
||||
break
|
||||
@@ -454,9 +852,9 @@ for BI in "${BUILT_IMAGES[@]}"; do
|
||||
fi
|
||||
done
|
||||
|
||||
# Also list detected images that weren't built locally (these are likely external images)
|
||||
# Also list push images that weren't built locally (these are likely prebuilt local images)
|
||||
NOT_BUILT_DETECTED=()
|
||||
for DI in "${IMAGES[@]}"; do
|
||||
for DI in "${PUSH_IMAGES[@]}"; do
|
||||
built=false
|
||||
for BI in "${BUILT_IMAGES[@]}"; do
|
||||
if [ "$DI" = "$BI" ]; then
|
||||
@@ -481,33 +879,44 @@ if [ "$BUILT_COUNT" -ne "$MATCHING_BUILT" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${#IMAGES[@]} -eq 0 ]; then
|
||||
if [ ${#PUSH_IMAGES[@]} -eq 0 ] && [ ${#EXTERNAL_IMAGES[@]} -eq 0 ]; then
|
||||
error "No images found in docker-compose.yml or built locally for project ${PROJECT_NAME}"
|
||||
fi
|
||||
|
||||
# Pre-pull unregistry image if needed
|
||||
UNREGISTRY_IMAGE="ghcr.io/psviderski/unregistry"
|
||||
if ! ssh "$SERVER" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -q '^${UNREGISTRY_IMAGE}$'" 2>/dev/null; then
|
||||
if ! ssh "$SERVER" "sudo docker images --format '{{.Repository}}:{{.Tag}}' | grep -q '^${UNREGISTRY_IMAGE}$'" 2>/dev/null; then
|
||||
substep "Pulling unregistry image (one-time setup)..."
|
||||
ssh "$SERVER" "docker pull ${UNREGISTRY_IMAGE}" > /dev/null 2>&1 || true
|
||||
ssh -tt "$SERVER" "sudo docker pull ${UNREGISTRY_IMAGE}"
|
||||
fi
|
||||
|
||||
# Transfer images
|
||||
step "Transferring images"
|
||||
PUSH_FAILED=0
|
||||
for IMAGE in "${IMAGES[@]}"; do
|
||||
for IMAGE in "${PUSH_IMAGES[@]}"; do
|
||||
substep "Pushing ${CYAN}$IMAGE${NC}..."
|
||||
if docker pussh "$IMAGE" "$SERVER"; then
|
||||
echo ""
|
||||
else
|
||||
echo -e " ${RED}✗${NC} Failed to push ${CYAN}$IMAGE${NC}"
|
||||
PUSH_FAILED=1
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $PUSH_FAILED -eq 1 ]; then
|
||||
error "Image transfer failed"
|
||||
# Pull external images directly on the server (no pussh)
|
||||
if [ ${#EXTERNAL_IMAGES[@]} -gt 0 ]; then
|
||||
step "Pulling external images on server"
|
||||
for IMAGE in "${EXTERNAL_IMAGES[@]}"; do
|
||||
substep "Pulling ${CYAN}$IMAGE${NC}..."
|
||||
# Allocate a TTY and do not redirect output so failures are visible.
|
||||
if ssh -tt "$SERVER" "sudo docker pull $(printf '%q' "$IMAGE")"; then
|
||||
echo ""
|
||||
else
|
||||
echo -e " ${RED}✗${NC} Failed to pull ${CYAN}$IMAGE${NC} on server"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Transfer files
|
||||
|
||||
Reference in New Issue
Block a user