#!/usr/bin/env bash # One-time server bootstrap for Ladill Link on 161.97.138.149 set -Eeuo pipefail APP_ROOT="/var/www/ladill-link" MONOLITH="/var/www/ladill.com/current" QR_PLUS_ENV="/var/www/ladill-qr-plus/shared/.env" NGINX_SETUP="/var/www/ladill.com/current/deployment/setup-service-subdomain-nginx.sh" RELEASE_ARCHIVE="${1:-/tmp/ladill-link-release.tgz}" log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*"; } [ -f "$RELEASE_ARCHIVE" ] || { echo "Missing release archive: $RELEASE_ARCHIVE" >&2; exit 1; } [ -f "$QR_PLUS_ENV" ] || { echo "Missing qr-plus env template" >&2; exit 1; } log "Creating app directories" mkdir -p "$APP_ROOT"/{releases,shared} chown -R deploy:www-data "$APP_ROOT" 2>/dev/null || true if [ ! -f "$APP_ROOT/shared/.env" ]; then log "Bootstrapping .env from qr-plus template" cp "$QR_PLUS_ENV" "$APP_ROOT/shared/.env" sed -i \ -e 's/^APP_NAME=.*/APP_NAME="Ladill Link"/' \ -e 's#^APP_URL=.*#APP_URL=https://link.ladill.com#' \ -e 's/^DB_DATABASE=.*/DB_DATABASE=ladill_link/' \ -e 's/^DB_USERNAME=.*/DB_USERNAME=ladill_link/' \ -e 's/^BILLING_API_KEY_QR=.*/BILLING_API_KEY_LINK=/' \ "$APP_ROOT/shared/.env" # Generate DB password + billing key if missing DB_PASS="$(openssl rand -hex 16)" BILL_KEY="$(openssl rand -hex 24)" sed -i "s/^DB_PASSWORD=.*/DB_PASSWORD=${DB_PASS}/" "$APP_ROOT/shared/.env" if ! grep -q '^BILLING_API_KEY_LINK=' "$APP_ROOT/shared/.env"; then echo "BILLING_API_KEY_LINK=${BILL_KEY}" >> "$APP_ROOT/shared/.env" else sed -i "s/^BILLING_API_KEY_LINK=.*/BILLING_API_KEY_LINK=${BILL_KEY}/" "$APP_ROOT/shared/.env" fi grep -q '^LINK_PUBLIC_DOMAIN=' "$APP_ROOT/shared/.env" || echo 'LINK_PUBLIC_DOMAIN=ladl.link' >> "$APP_ROOT/shared/.env" grep -q '^LINK_PRICE_PER_LINK_GHS=' "$APP_ROOT/shared/.env" || echo 'LINK_PRICE_PER_LINK_GHS=0.05' >> "$APP_ROOT/shared/.env" grep -q '^IDENTITY_API_KEY_LINK=' "$APP_ROOT/shared/.env" || echo "IDENTITY_API_KEY_LINK=$(openssl rand -hex 24)" >> "$APP_ROOT/shared/.env" chmod 640 "$APP_ROOT/shared/.env" chown deploy:www-data "$APP_ROOT/shared/.env" 2>/dev/null || true log "Creating MySQL database ladill_link" mysql -e "CREATE DATABASE IF NOT EXISTS ladill_link CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" mysql -e "CREATE USER IF NOT EXISTS 'ladill_link'@'127.0.0.1' IDENTIFIED BY '${DB_PASS}';" mysql -e "GRANT ALL PRIVILEGES ON ladill_link.* TO 'ladill_link'@'127.0.0.1';" mysql -e "FLUSH PRIVILEGES;" # Save keys for monolith wiring (picked up below) echo "$BILL_KEY" > /root/.ladill-link-bootstrap-billing-key echo "$DB_PASS" > /root/.ladill-link-bootstrap-db-pass fi log "Deploying release archive" export LADILL_APP_ROOT="$APP_ROOT" export LADILL_RELEASE_ARCHIVE="$RELEASE_ARCHIVE" bash "$APP_ROOT/releases/bootstrap-deploy.sh" 2>/dev/null || true # deploy.sh lives inside the archive — extract deploy helper first if needed TMP_EXTRACT="/tmp/ladill-link-deploy-$$" mkdir -p "$TMP_EXTRACT" tar -xzf "$RELEASE_ARCHIVE" -C "$TMP_EXTRACT" deploy/deploy.sh cp "$TMP_EXTRACT/deploy/deploy.sh" /tmp/ladill-link-deploy.sh LADILL_APP_ROOT="$APP_ROOT" LADILL_RELEASE_ARCHIVE="$RELEASE_ARCHIVE" bash /tmp/ladill-link-deploy.sh log "Configuring nginx for link.ladill.com" if [ -x "$NGINX_SETUP" ]; then bash "$NGINX_SETUP" link --app "$APP_ROOT/current" else bash /var/www/ladill.com/current/deployment/setup-service-subdomain-nginx.sh link --app "$APP_ROOT/current" 2>/dev/null || \ echo "WARN: run setup-service-subdomain-nginx.sh link manually" fi log "Configuring nginx for ladl.link" LADL_CONF="/etc/nginx/sites-available/ladl.link.conf" if [ ! -f "$LADL_CONF" ]; then cat > "$LADL_CONF" <<'NGINX' server { listen 80; listen [::]:80; server_name ladl.link www.ladl.link; root /var/www/ladill-link/current/public; location ^~ /.well-known/acme-challenge/ { allow all; } location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.4-fpm-ladill.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; } } NGINX ln -sf "$LADL_CONF" /etc/nginx/sites-enabled/ladl.link.conf nginx -t && systemctl reload nginx certbot certonly --webroot -w /var/www/ladill-link/current/public -d ladl.link -d www.ladl.link --non-interactive --agree-tos -m admin@ladill.com 2>/dev/null || \ certbot certonly --nginx -d ladl.link -d www.ladl.link --non-interactive --agree-tos -m admin@ladill.com 2>/dev/null || \ log "WARN: certbot for ladl.link failed — DNS may not point here yet" if [ -d /etc/letsencrypt/live/ladl.link ]; then cat > "$LADL_CONF" <<'NGINX' server { listen 80; listen [::]:80; server_name ladl.link www.ladl.link; location ^~ /.well-known/acme-challenge/ { root /var/www/ladill-link/current/public; allow all; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ladl.link www.ladl.link; client_max_body_size 64M; ssl_certificate /etc/letsencrypt/live/ladl.link/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ladl.link/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; root /var/www/ladill-link/current/public; index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.4-fpm-ladill.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; } location ~ /\.(?!well-known).* { deny all; } } NGINX nginx -t && systemctl reload nginx fi fi log "Wiring monolith billing + link DB (if monolith has link registry)" if [ -f "$MONOLITH/artisan" ]; then BILL_KEY="$(cat /root/.ladill-link-bootstrap-billing-key 2>/dev/null || grep '^BILLING_API_KEY_LINK=' "$APP_ROOT/shared/.env" | cut -d= -f2-)" MONO_ENV="/var/www/ladill.com/shared/.env" if [ -n "$BILL_KEY" ] && [ -f "$MONO_ENV" ]; then grep -q '^BILLING_API_KEY_LINK=' "$MONO_ENV" || echo "BILLING_API_KEY_LINK=${BILL_KEY}" >> "$MONO_ENV" grep -q '^LINK_DB_DATABASE=' "$MONO_ENV" || cat >> "$MONO_ENV" </dev/null; then (cd "$MONOLITH" && php artisan ladill:onboard-app link --run-dns) || true (cd "$MONOLITH" && php artisan dns:sync-subdomains) || true else log "Monolith missing link registry — deploy monolith code then re-run onboard" fi fi log "Bootstrap complete" curl -sI "https://link.ladill.com/up" 2>/dev/null | head -3 || curl -sI "http://link.ladill.com/up" 2>/dev/null | head -3 || true