143 lines
4.3 KiB
Bash
Executable File
143 lines
4.3 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
CMD="${SSH_ORIGINAL_COMMAND:-${1:-}}"
|
|
|
|
if [[ "$CMD" =~ ^cert-[a-zA-Z0-9._-]+$ ]]; then
|
|
APP="${CMD#cert-}"
|
|
|
|
# Subdomains (e.g., garage.hantim.net) don't have www variants
|
|
if [[ "$APP" == *.*.* ]]; then
|
|
CERT_DOMAINS="-d $APP"
|
|
SERVER_NAMES="$APP"
|
|
else
|
|
CERT_DOMAINS="-d $APP -d www.$APP"
|
|
SERVER_NAMES="$APP www.$APP"
|
|
fi
|
|
|
|
# Write temporary HTTP-only config so nginx can serve ACME challenges
|
|
cat > "/opt/hantim/docker/nginx/conf.d/$APP.conf" <<NGINXCONF
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name $SERVER_NAMES;
|
|
|
|
location /.well-known/acme-challenge/ {
|
|
root /var/www/certbot;
|
|
}
|
|
|
|
location / {
|
|
return 444;
|
|
}
|
|
}
|
|
NGINXCONF
|
|
|
|
trap 'git -C /opt/hantim restore "docker/nginx/conf.d/$APP.conf" 2>/dev/null || rm -f "/opt/hantim/docker/nginx/conf.d/$APP.conf"; docker exec nginx nginx -t && docker exec nginx nginx -s reload' EXIT
|
|
docker exec nginx nginx -t && docker exec nginx nginx -s reload
|
|
certbot certonly --webroot -w /opt/hantim/docker/nginx/certbot/www \
|
|
--non-interactive --agree-tos -m timothykim@fastmail.fm \
|
|
--cert-name "$APP" $CERT_DOMAINS
|
|
git -C /opt/hantim restore "docker/nginx/conf.d/$APP.conf" 2>/dev/null || rm -f "/opt/hantim/docker/nginx/conf.d/$APP.conf"
|
|
trap - EXIT
|
|
docker exec nginx nginx -t && docker exec nginx nginx -s reload
|
|
echo "Certificate issued for $APP"
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$CMD" = "provision" ]; then
|
|
cd /opt/hantim
|
|
git pull origin main
|
|
bash scripts/configure.sh
|
|
exit 0
|
|
fi
|
|
|
|
if ! [[ "$CMD" =~ ^deploy-[a-zA-Z0-9._-]+$ ]]; then
|
|
echo "Unknown command: $CMD"
|
|
exit 1
|
|
fi
|
|
|
|
APP="${CMD#deploy-}"
|
|
cd /opt/hantim
|
|
git pull origin main
|
|
|
|
# Re-exec so the running script reflects any changes just pulled
|
|
if [ -z "${DEPLOY_REEXEC:-}" ]; then
|
|
export DEPLOY_REEXEC=1
|
|
exec /opt/hantim/scripts/deploy.sh "$CMD"
|
|
fi
|
|
|
|
# Generate .env from bws if this service declares .env.keys
|
|
if [ -f "docker/$APP/.env.keys" ] && [ -f /etc/bws-token ]; then
|
|
export BWS_ACCESS_TOKEN
|
|
BWS_ACCESS_TOKEN=$(cat /etc/bws-token)
|
|
env_content=""
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
[ -z "$line" ] && continue
|
|
[[ "$line" = \#* ]] && continue
|
|
var_name="${line%%=*}"
|
|
secret_id="${line#*=}"
|
|
value=$(bws secret get "$secret_id" | jq -r .value)
|
|
if [ -z "$value" ]; then
|
|
echo "ERROR: Secret '$secret_id' not found in bws."
|
|
echo " Check that the secret exists and the machine account has access."
|
|
exit 1
|
|
fi
|
|
env_content="${env_content}${var_name}=${value}"$'\n'
|
|
done < "docker/$APP/.env.keys"
|
|
if [ -n "$env_content" ]; then
|
|
echo "Writing .env for $APP"
|
|
printf "%s" "$env_content" > "docker/$APP/.env"
|
|
chmod 600 "docker/$APP/.env"
|
|
fi
|
|
fi
|
|
|
|
cd "docker/$APP"
|
|
|
|
# Create directories marked with "# !create" in .gitignore
|
|
if [ -f .gitignore ]; then
|
|
create_next=false
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
if [ "$line" = "# !create" ]; then
|
|
create_next=true
|
|
continue
|
|
fi
|
|
if [ "$create_next" = true ] && [ -n "$line" ]; then
|
|
dir="${line%/}"
|
|
if [ -n "$dir" ]; then
|
|
mkdir -p "$dir"
|
|
echo "Created directory: $dir"
|
|
fi
|
|
create_next=false
|
|
fi
|
|
done < .gitignore
|
|
fi
|
|
|
|
if grep -q '^\s*build:' compose.yml 2>/dev/null; then
|
|
docker compose build
|
|
else
|
|
if ! docker compose pull; then
|
|
echo "Image not yet available for $APP — skipping. It will deploy when the app repo is first pushed."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
if [ "$APP" = "nginx" ]; then
|
|
# Fail loudly if any certs are missing — issue them first with: app.sh cert <domain>
|
|
for conf in /opt/hantim/docker/nginx/conf.d/*.*.conf; do
|
|
cert_name=$(basename "$conf" .conf)
|
|
if [ ! -d "/etc/letsencrypt/live/$cert_name" ]; then
|
|
echo "ERROR: Missing certificate for $cert_name"
|
|
echo " Run: app.sh cert $cert_name"
|
|
exit 1
|
|
fi
|
|
done
|
|
# Test config before applying — a bad config would take down all sites
|
|
docker compose run --rm -T nginx nginx -t
|
|
fi
|
|
|
|
docker compose up -d --remove-orphans
|
|
|
|
if [ "$APP" = "nginx" ]; then
|
|
docker exec nginx nginx -s reload
|
|
fi
|