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 {
|
fromchat.ru {
|
||||||
reverse_proxy frontend:8301 {
|
reverse_proxy frontend:8301 {
|
||||||
header_up X-Real-IP {remote_host}
|
header_up X-Real-IP {remote_host}
|
||||||
@@ -102,12 +117,4 @@ git.fromchat.ru {
|
|||||||
events 500
|
events 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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
|
- production
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "127.0.0.1:8080:8080"
|
||||||
- "443:443"
|
- "127.0.0.1:8443:8443"
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "host.docker.internal:host-gateway"
|
- "host.docker.internal:host-gateway"
|
||||||
volumes:
|
volumes:
|
||||||
@@ -179,6 +179,22 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- public
|
- 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:
|
postgres:
|
||||||
build:
|
build:
|
||||||
context: .
|
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
|
||||||
+529
-120
@@ -31,25 +31,19 @@ substep() {
|
|||||||
|
|
||||||
echo -e "${MAGENTA}${BOLD}🚀 Deployment${NC}\n"
|
echo -e "${MAGENTA}${BOLD}🚀 Deployment${NC}\n"
|
||||||
|
|
||||||
# Read password with asterisks
|
|
||||||
read_password() {
|
read_password() {
|
||||||
local password=""
|
local password=""
|
||||||
local char
|
local char
|
||||||
local old_stty
|
local old_stty
|
||||||
|
|
||||||
# Save current terminal settings
|
|
||||||
old_stty=$(stty -g 2>/dev/null)
|
old_stty=$(stty -g 2>/dev/null)
|
||||||
|
|
||||||
# Disable echo
|
|
||||||
stty -echo 2>/dev/null
|
stty -echo 2>/dev/null
|
||||||
|
|
||||||
# Read characters one by one
|
|
||||||
while IFS= read -rs -n 1 char; do
|
while IFS= read -rs -n 1 char; do
|
||||||
# Check for Enter key (empty means Enter was pressed)
|
|
||||||
if [ -z "$char" ]; then
|
if [ -z "$char" ]; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
# Check for backspace/delete (ASCII 127)
|
|
||||||
if [ "$char" = $'\177' ] || [ "$char" = $'\b' ]; then
|
if [ "$char" = $'\177' ] || [ "$char" = $'\b' ]; then
|
||||||
if [ ${#password} -gt 0 ]; then
|
if [ ${#password} -gt 0 ]; then
|
||||||
password="${password%?}"
|
password="${password%?}"
|
||||||
@@ -60,8 +54,7 @@ read_password() {
|
|||||||
printf "*" >&2
|
printf "*" >&2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Restore terminal settings
|
|
||||||
stty "$old_stty" 2>/dev/null
|
stty "$old_stty" 2>/dev/null
|
||||||
echo "" >&2
|
echo "" >&2
|
||||||
echo "$password"
|
echo "$password"
|
||||||
@@ -95,6 +88,20 @@ REPO_NAME="FromChat"
|
|||||||
DEPLOY_PATH="~/actions-runner/_work/$REPO_NAME/$REPO_NAME"
|
DEPLOY_PATH="~/actions-runner/_work/$REPO_NAME/$REPO_NAME"
|
||||||
PLATFORM="linux/arm64"
|
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
|
# Check if server is provided
|
||||||
if [ -z "$SERVER" ]; then
|
if [ -z "$SERVER" ]; then
|
||||||
error "Server not specified. Usage: $0 [user@host] [deployment_path] [platform]"
|
error "Server not specified. Usage: $0 [user@host] [deployment_path] [platform]"
|
||||||
@@ -146,48 +153,15 @@ if [ "$KEY_LOADED" = false ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if SSH key authentication already works
|
# 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
|
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
|
error "SSH key authentication failed for $SERVER"
|
||||||
true
|
echo " Copy your public key to the server, then re-run deploy:"
|
||||||
else
|
echo " ssh-copy-id -i \"$SSH_KEY_PUB_FILE\" \"$SERVER\""
|
||||||
# Check if our public key is already on the server
|
echo ""
|
||||||
KEY_CONTENT=$(cat "$SSH_KEY_PUB_FILE")
|
echo " Or manually append this key to ~/.ssh/authorized_keys on the server:"
|
||||||
if ssh -o BatchMode=no -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$SERVER" "
|
echo " $(cat "$SSH_KEY_PUB_FILE")"
|
||||||
grep -q '$KEY_CONTENT' ~/.ssh/authorized_keys 2>/dev/null
|
exit 1
|
||||||
" >/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."
|
|
||||||
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
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -195,15 +169,7 @@ fi
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
SUDO_PASSWORD=""
|
SUDO_PASSWORD=""
|
||||||
# If SSH password was provided, try using it for sudo first
|
# Prompt for sudo password (optional; leave blank for passwordless sudo)
|
||||||
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
|
|
||||||
if [ -z "$SUDO_PASSWORD" ]; then
|
if [ -z "$SUDO_PASSWORD" ]; then
|
||||||
while true; do
|
while true; do
|
||||||
substep "Sudo password: " -n
|
substep "Sudo password: " -n
|
||||||
@@ -266,11 +232,6 @@ start_docker_desktop() {
|
|||||||
return 1
|
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
|
# Check Docker daemon
|
||||||
if ! check_docker_daemon; then
|
if ! check_docker_daemon; then
|
||||||
warning "Docker daemon is not running"
|
warning "Docker daemon is not running"
|
||||||
@@ -279,35 +240,42 @@ if ! check_docker_daemon; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Setup buildx builder
|
if [ "$USE_DOCKER_BUILD" = false ]; then
|
||||||
step "Setting up buildx builder"
|
# Check buildx
|
||||||
BUILDER_NAME="fromchat-builder"
|
if ! docker buildx version > /dev/null 2>&1; then
|
||||||
BUILDER_EXISTS=false
|
error "Docker buildx not available. Install Docker Desktop."
|
||||||
|
|
||||||
if docker buildx inspect "$BUILDER_NAME" > /dev/null 2>&1; then
|
|
||||||
BUILDER_EXISTS=true
|
|
||||||
if ! docker buildx use "$BUILDER_NAME" > /dev/null 2>&1; then
|
|
||||||
substep "Recreating builder..."
|
|
||||||
docker buildx rm "$BUILDER_NAME" > /dev/null 2>&1 || true
|
|
||||||
BUILDER_EXISTS=false
|
|
||||||
elif ! docker buildx inspect "$BUILDER_NAME" > /dev/null 2>&1; then
|
|
||||||
substep "Recreating builder (inspection failed)..."
|
|
||||||
docker buildx rm "$BUILDER_NAME" > /dev/null 2>&1 || true
|
|
||||||
BUILDER_EXISTS=false
|
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$BUILDER_EXISTS" = false ]; then
|
# Setup buildx builder
|
||||||
substep "Creating builder with persistent cache..."
|
step "Setting up buildx builder"
|
||||||
docker buildx create \
|
BUILDER_NAME="fromchat-builder"
|
||||||
--name "$BUILDER_NAME" \
|
BUILDER_EXISTS=false
|
||||||
--driver docker-container \
|
|
||||||
--driver-opt image=moby/buildkit:latest \
|
|
||||||
--use \
|
|
||||||
--bootstrap > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker buildx use "$BUILDER_NAME" > /dev/null 2>&1
|
if docker buildx inspect "$BUILDER_NAME" > /dev/null 2>&1; then
|
||||||
|
BUILDER_EXISTS=true
|
||||||
|
if ! docker buildx use "$BUILDER_NAME" > /dev/null 2>&1; then
|
||||||
|
substep "Recreating builder..."
|
||||||
|
docker buildx rm "$BUILDER_NAME" > /dev/null 2>&1 || true
|
||||||
|
BUILDER_EXISTS=false
|
||||||
|
elif ! docker buildx inspect "$BUILDER_NAME" > /dev/null 2>&1; then
|
||||||
|
substep "Recreating builder (inspection failed)..."
|
||||||
|
docker buildx rm "$BUILDER_NAME" > /dev/null 2>&1 || true
|
||||||
|
BUILDER_EXISTS=false
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$BUILDER_EXISTS" = false ]; then
|
||||||
|
substep "Creating builder with persistent cache..."
|
||||||
|
docker buildx create \
|
||||||
|
--name "$BUILDER_NAME" \
|
||||||
|
--driver docker-container \
|
||||||
|
--driver-opt image=moby/buildkit:latest \
|
||||||
|
--use \
|
||||||
|
--bootstrap > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker buildx use "$BUILDER_NAME" > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
# Detect services
|
# Detect services
|
||||||
step "Detecting services"
|
step "Detecting services"
|
||||||
@@ -378,20 +346,439 @@ for SERVICE in $SERVICES; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BUILDX_ARGS=(buildx build --platform "$PLATFORM" --file "$DOCKERFILE" --tag "$IMAGE_TAG" --load)
|
if [ "$USE_DOCKER_BUILD" = true ]; then
|
||||||
if [ -n "$BUILD_TARGET" ]; then
|
DOCKER_BUILD_ARGS=(build --platform "$PLATFORM" --file "$DOCKERFILE" --tag "$IMAGE_TAG")
|
||||||
BUILDX_ARGS+=(--target "$BUILD_TARGET")
|
if [ -n "$BUILD_TARGET" ]; then
|
||||||
fi
|
DOCKER_BUILD_ARGS+=(--target "$BUILD_TARGET")
|
||||||
BUILDX_ARGS+=("$BUILD_CONTEXT")
|
fi
|
||||||
|
DOCKER_BUILD_ARGS+=("$BUILD_CONTEXT")
|
||||||
|
|
||||||
if docker "${BUILDX_ARGS[@]}"; then
|
if docker "${DOCKER_BUILD_ARGS[@]}"; then
|
||||||
echo -e " ${GREEN}✓${NC} Built ${CYAN}$SERVICE${NC}"
|
echo -e " ${GREEN}✓${NC} Built ${CYAN}$SERVICE${NC}"
|
||||||
BUILT_IMAGES+=("$IMAGE_TAG")
|
BUILT_IMAGES+=("$IMAGE_TAG")
|
||||||
echo ""
|
echo ""
|
||||||
|
else
|
||||||
|
error "Build failed for $SERVICE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
error "Build failed for $SERVICE"
|
# On macOS Docker Desktop, --load can hang for a long time at "sending tarball".
|
||||||
exit 1
|
# 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
|
||||||
|
BUILDX_ARGS+=("$BUILD_CONTEXT")
|
||||||
|
|
||||||
|
if docker "${BUILDX_ARGS[@]}"; then
|
||||||
|
echo -e " ${GREEN}✓${NC} Built ${CYAN}$SERVICE${NC}"
|
||||||
|
BUILT_IMAGES+=("$IMAGE_TAG")
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
error "Build failed for $SERVICE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
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
|
done
|
||||||
|
|
||||||
success "Build complete! ${#BUILT_IMAGES[@]} image(s) ready"
|
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)
|
# Detect images based on docker-compose.yml (prefer explicit `image:` entries; fall back to built tags)
|
||||||
cd "$DEPLOYMENT_DIR"
|
cd "$DEPLOYMENT_DIR"
|
||||||
COMPOSE_SERVICES=$(docker compose -f docker-compose.yml config --services 2>/dev/null || true)
|
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
|
for S in $COMPOSE_SERVICES; do
|
||||||
IMAGE_FROM_COMPOSE=$(jq -r --arg s "$S" '.services[$s].image // empty' <<< "$COMPOSE_JSON")
|
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
|
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
|
else
|
||||||
# If service has a build section (we built it above), use the tag pattern used during build
|
# If service has a build section (we built it above), use the tag pattern used during build
|
||||||
TAG="${PROJECT_NAME}-${S}:latest"
|
TAG="${PROJECT_NAME}-${S}:latest"
|
||||||
# Only include the tag if the image exists locally (avoid pushing unrelated images)
|
# Only include the tag if the image exists locally (avoid pushing unrelated images)
|
||||||
if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "^${TAG}$"; then
|
if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "^${TAG}$"; then
|
||||||
IMAGES+=("$TAG")
|
PUSH_IMAGES+=("$TAG")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Deduplicate while preserving order
|
# Deduplicate while preserving order
|
||||||
if [ ${#IMAGES[@]} -gt 0 ]; then
|
if [ ${#PUSH_IMAGES[@]} -gt 0 ]; then
|
||||||
IMAGES=($(printf "%s\n" "${IMAGES[@]}" | awk '!seen[$0]++'))
|
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
|
fi
|
||||||
|
|
||||||
# Verify that all built images are among the detected images to be pushed.
|
# Verify that all built images are among the detected images to be pushed.
|
||||||
@@ -441,7 +839,7 @@ MATCHING_BUILT=0
|
|||||||
MISSING_FROM_DETECTED=()
|
MISSING_FROM_DETECTED=()
|
||||||
for BI in "${BUILT_IMAGES[@]}"; do
|
for BI in "${BUILT_IMAGES[@]}"; do
|
||||||
found=false
|
found=false
|
||||||
for DI in "${IMAGES[@]}"; do
|
for DI in "${PUSH_IMAGES[@]}"; do
|
||||||
if [ "$BI" = "$DI" ]; then
|
if [ "$BI" = "$DI" ]; then
|
||||||
found=true
|
found=true
|
||||||
break
|
break
|
||||||
@@ -454,9 +852,9 @@ for BI in "${BUILT_IMAGES[@]}"; do
|
|||||||
fi
|
fi
|
||||||
done
|
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=()
|
NOT_BUILT_DETECTED=()
|
||||||
for DI in "${IMAGES[@]}"; do
|
for DI in "${PUSH_IMAGES[@]}"; do
|
||||||
built=false
|
built=false
|
||||||
for BI in "${BUILT_IMAGES[@]}"; do
|
for BI in "${BUILT_IMAGES[@]}"; do
|
||||||
if [ "$DI" = "$BI" ]; then
|
if [ "$DI" = "$BI" ]; then
|
||||||
@@ -481,33 +879,44 @@ if [ "$BUILT_COUNT" -ne "$MATCHING_BUILT" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
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}"
|
error "No images found in docker-compose.yml or built locally for project ${PROJECT_NAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pre-pull unregistry image if needed
|
# Pre-pull unregistry image if needed
|
||||||
UNREGISTRY_IMAGE="ghcr.io/psviderski/unregistry"
|
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)..."
|
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
|
fi
|
||||||
|
|
||||||
# Transfer images
|
# Transfer images
|
||||||
step "Transferring images"
|
step "Transferring images"
|
||||||
PUSH_FAILED=0
|
for IMAGE in "${PUSH_IMAGES[@]}"; do
|
||||||
for IMAGE in "${IMAGES[@]}"; do
|
|
||||||
substep "Pushing ${CYAN}$IMAGE${NC}..."
|
substep "Pushing ${CYAN}$IMAGE${NC}..."
|
||||||
if docker pussh "$IMAGE" "$SERVER"; then
|
if docker pussh "$IMAGE" "$SERVER"; then
|
||||||
echo ""
|
echo ""
|
||||||
else
|
else
|
||||||
echo -e " ${RED}✗${NC} Failed to push ${CYAN}$IMAGE${NC}"
|
echo -e " ${RED}✗${NC} Failed to push ${CYAN}$IMAGE${NC}"
|
||||||
PUSH_FAILED=1
|
|
||||||
echo ""
|
echo ""
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ $PUSH_FAILED -eq 1 ]; then
|
# Pull external images directly on the server (no pussh)
|
||||||
error "Image transfer failed"
|
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
|
fi
|
||||||
|
|
||||||
# Transfer files
|
# Transfer files
|
||||||
|
|||||||
Reference in New Issue
Block a user