feat: adapt deployment for existing Docker server with nginx-proxy + Woodpecker
- docker-compose.yaml: remove port binding; add VIRTUAL_HOST/LETSENCRYPT_HOST env vars for nginx-proxy auto-routing; add internal + external proxy networks - .woodpecker.yml: consolidate build steps into single ci step; add deploy-main step that builds + deploys on every push to main; keep deploy-tag for registry-pull deploys on version tags - deploy/deploy.sh: simplify for manual/emergency use on existing server; add --from-registry flag for registry pull vs local build - Remove deploy/setup-server.sh and deploy/nginx/ (not needed on existing server) Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
f99772d8c0
commit
f29b39b40c
@ -1,18 +1,10 @@
|
||||
steps:
|
||||
- name: build
|
||||
image: golang:1.22-alpine
|
||||
commands:
|
||||
- go build ./cmd/server/
|
||||
|
||||
- name: vet
|
||||
- name: ci
|
||||
image: golang:1.22-alpine
|
||||
commands:
|
||||
- go vet ./...
|
||||
|
||||
- name: test
|
||||
image: golang:1.22-alpine
|
||||
commands:
|
||||
- go test ./...
|
||||
- go build ./cmd/server/
|
||||
|
||||
- name: docker-build
|
||||
image: plugins/docker
|
||||
@ -30,7 +22,7 @@ steps:
|
||||
event: tag
|
||||
ref: refs/tags/v*
|
||||
|
||||
- name: deploy
|
||||
- name: deploy-tag
|
||||
image: appleboy/drone-ssh
|
||||
settings:
|
||||
host:
|
||||
@ -41,8 +33,30 @@ steps:
|
||||
from_secret: deploy_key
|
||||
script:
|
||||
- cd /opt/cast-ghl-provider
|
||||
- docker compose pull
|
||||
- docker compose pull bridge
|
||||
- docker compose up -d --remove-orphans
|
||||
- sleep 5
|
||||
- docker compose ps bridge
|
||||
when:
|
||||
event: tag
|
||||
ref: refs/tags/v*
|
||||
|
||||
- name: deploy-main
|
||||
image: appleboy/drone-ssh
|
||||
settings:
|
||||
host:
|
||||
from_secret: deploy_host
|
||||
username:
|
||||
from_secret: deploy_user
|
||||
key:
|
||||
from_secret: deploy_key
|
||||
script:
|
||||
- cd /opt/cast-ghl-provider
|
||||
- git pull --ff-only
|
||||
- docker compose build --no-cache bridge
|
||||
- docker compose up -d --remove-orphans
|
||||
- sleep 5
|
||||
- docker compose ps bridge
|
||||
when:
|
||||
branch: main
|
||||
event: push
|
||||
|
||||
@ -1,33 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh — Pull latest code and redeploy via Docker Compose
|
||||
# Run from /opt/cast-ghl-plugin after initial server setup.
|
||||
# Usage: bash deploy/deploy.sh
|
||||
# deploy.sh — Manual redeploy on an existing Docker server.
|
||||
# Normally Woodpecker CI handles deploys automatically on push to main or tag.
|
||||
# Use this script only for manual/emergency redeploys.
|
||||
# Usage: bash deploy/deploy.sh [--from-registry]
|
||||
# --from-registry Pull the pre-built image from registry instead of building locally
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
APP_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$APP_DIR"
|
||||
|
||||
FROM_REGISTRY=false
|
||||
[[ "${1:-}" == "--from-registry" ]] && FROM_REGISTRY=true
|
||||
|
||||
echo "==> Pulling latest code"
|
||||
git pull --ff-only
|
||||
|
||||
echo "==> Building and restarting services"
|
||||
docker compose pull mongo # pull latest Mongo image if updated
|
||||
if $FROM_REGISTRY; then
|
||||
echo "==> Pulling pre-built image from registry"
|
||||
docker compose pull bridge
|
||||
else
|
||||
echo "==> Building image locally"
|
||||
docker compose build --no-cache bridge
|
||||
fi
|
||||
|
||||
echo "==> Restarting services"
|
||||
docker compose up -d --remove-orphans
|
||||
|
||||
echo "==> Waiting for health check"
|
||||
sleep 5
|
||||
STATUS=$(docker compose ps --format json | python3 -c "
|
||||
import sys, json
|
||||
for line in sys.stdin:
|
||||
s = json.loads(line)
|
||||
if s.get('Service') == 'bridge':
|
||||
print(s.get('Health', s.get('State', 'unknown')))
|
||||
" 2>/dev/null || echo "unknown")
|
||||
echo "Bridge container status: $STATUS"
|
||||
|
||||
echo "==> Tailing last 20 log lines"
|
||||
docker compose ps bridge
|
||||
docker compose logs --tail=20 bridge
|
||||
|
||||
echo ""
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name ghl.cast.ph;
|
||||
|
||||
# Let's Encrypt ACME challenge
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name ghl.cast.ph;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/ghl.cast.ph/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/ghl.cast.ph/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header Referrer-Policy no-referrer;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3002;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Timeouts — GHL expects quick 200 for webhook; 30s is generous
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# setup-server.sh — Bootstrap a fresh Ubuntu 22.04/24.04 LTS Vultr VPS
|
||||
# Run once as root (or with sudo) after provisioning.
|
||||
# Usage: bash setup-server.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOMAIN="ghl.cast.ph"
|
||||
APP_DIR="/opt/cast-ghl-plugin"
|
||||
REPO_URL="https://github.com/CAST-ph/cast-ghl-plugin.git" # adjust if needed
|
||||
|
||||
echo "==> Updating system packages"
|
||||
apt-get update -q && apt-get upgrade -y -q
|
||||
|
||||
echo "==> Installing dependencies"
|
||||
apt-get install -y -q \
|
||||
ca-certificates curl gnupg ufw \
|
||||
nginx certbot python3-certbot-nginx \
|
||||
git
|
||||
|
||||
echo "==> Installing Docker"
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/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/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
||||
| tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
apt-get update -q
|
||||
apt-get install -y -q docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
systemctl enable --now docker
|
||||
|
||||
echo "==> Configuring firewall"
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
ufw allow ssh
|
||||
ufw allow 'Nginx Full'
|
||||
ufw --force enable
|
||||
|
||||
echo "==> Cloning application"
|
||||
mkdir -p "$APP_DIR"
|
||||
if [ -d "$APP_DIR/.git" ]; then
|
||||
git -C "$APP_DIR" pull
|
||||
else
|
||||
git clone "$REPO_URL" "$APP_DIR"
|
||||
fi
|
||||
|
||||
echo "==> Installing Nginx config"
|
||||
cp "$APP_DIR/deploy/nginx/ghl.cast.ph.conf" /etc/nginx/sites-available/"$DOMAIN"
|
||||
ln -sf /etc/nginx/sites-available/"$DOMAIN" /etc/nginx/sites-enabled/"$DOMAIN"
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
nginx -t && systemctl reload nginx
|
||||
|
||||
echo "==> Obtaining Let's Encrypt certificate"
|
||||
certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos -m ops@cast.ph
|
||||
systemctl reload nginx
|
||||
|
||||
echo ""
|
||||
echo "=== Setup complete ==="
|
||||
echo "Next: copy .env to $APP_DIR/.env then run deploy/deploy.sh"
|
||||
@ -1,13 +1,20 @@
|
||||
services:
|
||||
bridge:
|
||||
build: .
|
||||
# Bind to localhost only — Nginx proxies from outside
|
||||
ports:
|
||||
- "127.0.0.1:${PORT:-3002}:${PORT:-3002}"
|
||||
# No port binding — nginx-proxy routes traffic via the shared proxy network
|
||||
env_file: .env
|
||||
environment:
|
||||
# nginx-proxy / acme-companion auto-routing
|
||||
- VIRTUAL_HOST=${VIRTUAL_HOST:-ghl.cast.ph}
|
||||
- VIRTUAL_PORT=${PORT:-3002}
|
||||
- LETSENCRYPT_HOST=${VIRTUAL_HOST:-ghl.cast.ph}
|
||||
- LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL:-ops@cast.ph}
|
||||
depends_on:
|
||||
mongo:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- internal
|
||||
- proxy # shared nginx-proxy network — must match the nginx-proxy container's network
|
||||
restart: unless-stopped
|
||||
logging:
|
||||
driver: json-file
|
||||
@ -20,6 +27,8 @@ services:
|
||||
# No ports exposed — only reachable by bridge on the internal network
|
||||
volumes:
|
||||
- mongo-data:/data/db
|
||||
networks:
|
||||
- internal
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
@ -28,5 +37,13 @@ services:
|
||||
retries: 5
|
||||
start_period: 20s
|
||||
|
||||
networks:
|
||||
internal:
|
||||
# Private network for bridge ↔ mongo
|
||||
proxy:
|
||||
external: true
|
||||
# Must match the name of the existing nginx-proxy Docker network on the server.
|
||||
# Check with: docker network ls | grep proxy
|
||||
|
||||
volumes:
|
||||
mongo-data:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user