#!/usr/bin/env bash # ===================================================================== # Create (or update) the standard LogShip ERP proxy host in Nginx Proxy Manager # --------------------------------------------------------------------- # add-instance.sh [--cert ] [--disabled] [--letsencrypt ] # # --cert certificate to use (create default: "selfsigned-wildcard"; update default: keep current) # --letsencrypt request a Let's Encrypt cert via http-01 (DNS must already point at the # edge IP and 80/443 must be forwarded) instead of --cert # --disabled create the host disabled (ready, not serving) # # Standard per-instance routing (one source of truth, see README): # / http://IP:3001 websockets on, X-Forwarded-Proto, buffers # /api/v1 https://IP:8443/api/v1 (iDempiere REST, self-signed upstream) # /webui, /webui/serverpush https://IP:8443 (ZK UI, websocket, 300 s) # /media-api http://IP:1337/api (Strapi) # /files-api http://IP:80/ (instance nginx -> uploads) # /capi/webhooks/fulfillment-leads/ http://IP:3001 (landing-page lead webhook) # ~ ^/api/.*/stream$ http://IP:3001 SSE: no buffering, 1 h read } advanced-snippet.conf # /chat/ws http://IP:3001 websocket, 1 h read } # Needs: curl, jq. Runs anywhere that reaches the NPM API (edge VM itself, or your Mac). # ===================================================================== set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" # shellcheck source=npm-api.sh source "$HERE/npm-api.sh" [ $# -ge 2 ] || { grep '^# ' "$0" | sed 's/^# //'; exit 1; } DOMAIN="$1"; IP="$2"; shift 2 CERT=""; ENABLED=1; LE_EMAIL="" # empty CERT = keep existing on update / selfsigned-wildcard on create while [ $# -gt 0 ]; do case "$1" in --cert) CERT="$2"; shift 2;; --letsencrypt) LE_EMAIL="$2"; shift 2;; --disabled) ENABLED=0; shift;; *) echo "unknown option $1" >&2; exit 1;; esac done npm_login snippet=$(sed "s/__IP__/$IP/g" "$HERE/advanced-snippet.conf") loc_webui=$(cat "$HERE/location-webui.conf") loc_api=$(cat "$HERE/location-api.conf") existing=$(npm_host_id_by_domain "$DOMAIN") cert_id=0; meta='{"letsencrypt_agree":false,"dns_challenge":false}' if [ -z "$CERT" ] && [ -z "$LE_EMAIL" ]; then if [ -n "$existing" ]; then cert_id=$(npm_get "/api/nginx/proxy-hosts/$existing" | jq -r '.certificate_id // 0') # keep what the host has else CERT="selfsigned-wildcard" fi fi if [ -n "$LE_EMAIL" ]; then meta=$(jq -n --arg e "$LE_EMAIL" '{letsencrypt_agree:true, letsencrypt_email:$e, dns_challenge:false}') cert_id='"new"' elif [[ "$CERT" =~ ^[0-9]+$ ]]; then cert_id="$CERT" elif [ -n "$CERT" ]; then cert_id=$(npm_cert_id_by_name "$CERT"); [ -n "$cert_id" ] || { echo "certificate '$CERT' not found" >&2; exit 1; } fi body=$(jq -n \ --arg d "$DOMAIN" --arg ip "$IP" --arg adv "$snippet" --arg lw "$loc_webui" --arg la "$loc_api" \ --argjson cert "$cert_id" --argjson en "$ENABLED" --argjson meta "$meta" ' { domain_names: [$d], forward_scheme: "http", forward_host: $ip, forward_port: 3001, certificate_id: $cert, ssl_forced: true, http2_support: true, hsts_enabled: true, hsts_subdomains: false, block_exploits: true, caching_enabled: false, allow_websocket_upgrade: true, access_list_id: 0, advanced_config: $adv, enabled: $en, meta: $meta, locations: [ { path: "/api/v1", forward_scheme: "https", forward_host: $ip, forward_port: 8443, forward_path: "/api/v1", advanced_config: $la }, { path: "/webui", forward_scheme: "https", forward_host: $ip, forward_port: 8443, forward_path: "/webui", advanced_config: $lw }, { path: "/webui/serverpush", forward_scheme: "https", forward_host: $ip, forward_port: 8443, forward_path: "/webui/serverpush", advanced_config: $lw }, { path: "/media-api", forward_scheme: "http", forward_host: $ip, forward_port: 1337, forward_path: "/api", advanced_config: "" }, { path: "/files-api", forward_scheme: "http", forward_host: $ip, forward_port: 80, forward_path: "/", advanced_config: "" }, { path: "/capi/webhooks/fulfillment-leads/", forward_scheme: "http", forward_host: $ip, forward_port: 3001, advanced_config: "" } ] }') if [ -n "$existing" ]; then out=$(npm_put "/api/nginx/proxy-hosts/$existing" "$(echo "$body" | jq 'del(.enabled)')") echo "updated proxy host #$existing $DOMAIN -> $IP" else out=$(npm_post /api/nginx/proxy-hosts "$body") echo "created proxy host #$(echo "$out" | jq -r .id) $DOMAIN -> $IP (enabled=$ENABLED, cert=$(echo "$out" | jq -r .certificate_id))" fi