Download install-nginx.sh from AnthropicallyHuggingFaces/nginx-api-key-proxy: direct link, hf CLI and curl.
- Browser
- Download file 12.6 kB
-
https://huggingface.co/spaces/AnthropicallyHuggingFaces/nginx-api-key-proxy/resolve/main/install-nginx.sh
- Command line
-
hf download hf://spaces/AnthropicallyHuggingFaces/nginx-api-key-proxy/install-nginx.sh
-
curl -L -o install-nginx.sh https://huggingface.co/spaces/AnthropicallyHuggingFaces/nginx-api-key-proxy/resolve/main/install-nginx.sh
12.6 kB
| set -euo pipefail | |
| # =========================================================================== | |
| # install-nginx.sh | |
| # Builds nginx from source, wires up a systemd unit, and configures a | |
| # reverse proxy that injects an upstream API key server-side. | |
| # | |
| # The API key is resolved automatically (Vault / AWS Secrets Manager / | |
| # local files / systemd units), stored ONLY in a root-only runtime env | |
| # file, and is never written into nginx.conf. | |
| # =========================================================================== | |
| # --------------------------------------------------------------------------- | |
| # Variables | |
| # --------------------------------------------------------------------------- | |
| NGINX_VERSION=1.25.3 | |
| INSTALL_PATH=/usr/local/nginx | |
| SERVICE_FILE=/etc/systemd/system/nginx.service | |
| TEMPLATE_FILE=/tmp/nginx.conf.template | |
| # Runtime env file consumed by systemd -> nginx master process. | |
| # This is where the ONLY copy of the key lives at rest (chmod 600, root). | |
| RUNTIME_ENV=/etc/nginx-upstream.env | |
| SECRET_FILE=/etc/nginx-secrets.env # legacy/cache; read for back-compat | |
| DEFAULT_API_KEY="__REPLACE_ME__" | |
| # --- HashiCorp Vault ------------------------------------------------------- | |
| VAULT_ADDR="${VAULT_ADDR:-}" | |
| VAULT_SECRET_PATH="${VAULT_SECRET_PATH:-}" | |
| VAULT_SECRET_FIELD="${VAULT_SECRET_FIELD:-api_key}" | |
| VAULT_TOKEN_FILE="${VAULT_TOKEN_FILE:-/etc/vault-token}" | |
| # AppRole (used only if no token above is available) | |
| VAULT_ROLE_ID="${VAULT_ROLE_ID:-}" | |
| VAULT_SECRET_ID_FILE="${VAULT_SECRET_ID_FILE:-/etc/vault-approle-secret-id}" | |
| # --- AWS Secrets Manager --------------------------------------------------- | |
| AWS_SECRET_ID="${AWS_SECRET_ID:-}" | |
| AWS_SECRET_FIELD="${AWS_SECRET_FIELD:-api_key}" | |
| AWS_REGION="${AWS_REGION:-${AWS_DEFAULT_REGION:-us-east-1}}" | |
| # --- Heuristic local sources ---------------------------------------------- | |
| LOCAL_KEY_SOURCES=( | |
| "/etc/myapp/api.key" | |
| "/etc/myapp/secrets.env" | |
| "/opt/app/.env" | |
| "/etc/environment" | |
| ) | |
| BACKEND_UNITS=( "myapp.service" "model-api.service" ) | |
| # --------------------------------------------------------------------------- | |
| # Helpers | |
| # --------------------------------------------------------------------------- | |
| log() { printf '[setup] %s\n' "$*"; } | |
| warn() { printf '[setup][warn] %s\n' "$*" >&2; } | |
| ensure_secret_tools() { | |
| if [[ -n "$VAULT_SECRET_PATH" || -n "$AWS_SECRET_ID" ]]; then | |
| apt-get update -qq || true | |
| apt-get install -y jq >/dev/null 2>&1 || warn "jq unavailable; using sed fallback" | |
| fi | |
| if [[ -n "$AWS_SECRET_ID" ]] && ! command -v aws >/dev/null 2>&1; then | |
| apt-get install -y awscli >/dev/null 2>&1 || warn "awscli not installable" | |
| fi | |
| } | |
| # Extract the first API key-ish value from a KEY=VALUE style file. | |
| key_from_envfile() { | |
| local file="$1" name val | |
| [[ -r "$file" ]] || return 1 | |
| while IFS='=' read -r name val; do | |
| name="${name//[[:space:]]/}"; name="${name#export}" | |
| case "$name" in | |
| UPSTREAM_API_KEY|API_KEY|OPENAI_API_KEY|MODEL_API_KEY|LLM_API_KEY) | |
| val="${val%%#*}"; val="${val//\"/}"; val="${val//\'/}" | |
| val="${val//[[:space:]]/}" | |
| [[ -n "$val" ]] && { printf '%s' "$val"; return 0; } | |
| ;; | |
| esac | |
| done < "$file" | |
| return 1 | |
| } | |
| # Whole file (trimmed) is the key. | |
| key_from_keyfile() { | |
| local file="$1" | |
| [[ -r "$file" ]] || return 1 | |
| tr -d '[:space:]' < "$file" | head -c 512 | |
| } | |
| # Mine a systemd unit for EnvironmentFile= / Environment= keys. | |
| key_from_systemd_unit() { | |
| local unit="$1" unitfile ef found inline | |
| for dir in /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system; do | |
| unitfile="$dir/$unit" | |
| [[ -f "$unitfile" ]] || continue | |
| while read -r ef; do | |
| ef="${ef#-}" | |
| found="$(key_from_envfile "$ef" 2>/dev/null || true)" | |
| [[ -n "$found" ]] && { printf '%s' "$found"; return 0; } | |
| done < <(sed -nE 's/^[[:space:]]*EnvironmentFile=//p' "$unitfile") | |
| inline="$(sed -nE \ | |
| 's/.*(UPSTREAM_API_KEY|API_KEY|OPENAI_API_KEY|MODEL_API_KEY|LLM_API_KEY)=([^[:space:]]+).*/\2/p' \ | |
| "$unitfile" | head -n1)" | |
| [[ -n "$inline" ]] && { printf '%s' "$inline"; return 0; } | |
| done | |
| return 1 | |
| } | |
| # --- Vault: token file, then AppRole -------------------------------------- | |
| vault_login() { | |
| # Prefer an existing VAULT_TOKEN; else token file; else AppRole. | |
| if [[ -z "${VAULT_TOKEN:-}" && -r "$VAULT_TOKEN_FILE" ]]; then | |
| VAULT_TOKEN="$(<"$VAULT_TOKEN_FILE")" | |
| fi | |
| if [[ -n "${VAULT_TOKEN:-}" ]]; then | |
| printf '%s' "$VAULT_TOKEN"; return 0 | |
| fi | |
| # AppRole login: role_id + secret_id (from file), token captured in-var only. | |
| [[ -n "$VAULT_ROLE_ID" && -r "$VAULT_SECRET_ID_FILE" ]] || return 1 | |
| local secret_id resp tok | |
| secret_id="$(<"$VAULT_SECRET_ID_FILE")" | |
| resp="$(vault write -format=json auth/approle/login \ | |
| role_id="$VAULT_ROLE_ID" secret_id="$secret_id" 2>/dev/null)" || return 1 | |
| if command -v jq >/dev/null 2>&1; then | |
| tok="$(printf '%s' "$resp" | jq -r '.auth.client_token // empty')" | |
| else | |
| tok="$(printf '%s' "$resp" | sed -nE 's/.*"client_token"[: ]*"([^"]+)".*/\1/p' | head -n1)" | |
| fi | |
| [[ -n "$tok" ]] || return 1 | |
| printf '%s' "$tok" | |
| } | |
| key_from_vault() { | |
| command -v vault >/dev/null 2>&1 || return 1 | |
| [[ -n "$VAULT_ADDR" && -n "$VAULT_SECRET_PATH" ]] || return 1 | |
| export VAULT_ADDR | |
| VAULT_TOKEN="$(vault_login)" || return 1 | |
| export VAULT_TOKEN | |
| vault kv get -field="$VAULT_SECRET_FIELD" "$VAULT_SECRET_PATH" 2>/dev/null | |
| } | |
| # --- AWS Secrets Manager --------------------------------------------------- | |
| key_from_aws() { | |
| command -v aws >/dev/null 2>&1 || return 1 | |
| [[ -n "$AWS_SECRET_ID" ]] || return 1 | |
| export AWS_REGION | |
| local secret | |
| secret="$(aws secretsmanager get-secret-value \ | |
| --secret-id "$AWS_SECRET_ID" \ | |
| --query SecretString --output text 2>/dev/null)" || return 1 | |
| [[ -n "$secret" ]] || return 1 | |
| if command -v jq >/dev/null 2>&1; then | |
| printf '%s' "$secret" | jq -r --arg k "$AWS_SECRET_FIELD" '.[$k] // empty' | |
| else | |
| printf '%s' "$secret" \ | |
| | sed -nE "s/.*\"${AWS_SECRET_FIELD}\"[[:space:]]*:[[:space:]]*\"([^\"]+)\".*/\1/p" | head -n1 | |
| fi | |
| } | |
| # =========================================================================== | |
| # 0a. Resolve the key (env / cache / Vault / AWS / local / placeholder) | |
| # =========================================================================== | |
| [[ -f "$SECRET_FILE" ]] && { source "$SECRET_FILE"; } | |
| [[ -f "$RUNTIME_ENV" ]] && { source "$RUNTIME_ENV"; } | |
| : "${UPSTREAM_URL:=http://127.0.0.1:5000/}" | |
| : "${LISTEN_PORT:=80}" | |
| if [[ -z "${UPSTREAM_API_KEY:-}" ]]; then | |
| ensure_secret_tools | |
| log "No UPSTREAM_API_KEY set; resolving from configured sources..." | |
| candidate="" | |
| if [[ -n "$VAULT_SECRET_PATH" ]]; then | |
| candidate="$(key_from_vault || true)" | |
| [[ -n "$candidate" ]] && log "Fetched key from Vault ($VAULT_SECRET_PATH)" | |
| fi | |
| if [[ -z "$candidate" && -n "$AWS_SECRET_ID" ]]; then | |
| candidate="$(key_from_aws || true)" | |
| [[ -n "$candidate" ]] && log "Fetched key from AWS Secrets Manager ($AWS_SECRET_ID)" | |
| fi | |
| if [[ -z "$candidate" ]]; then | |
| for src in "${LOCAL_KEY_SOURCES[@]}"; do | |
| if [[ "$src" == *.key ]]; then | |
| candidate="$(key_from_keyfile "$src" 2>/dev/null || true)" | |
| else | |
| candidate="$(key_from_envfile "$src" 2>/dev/null || true)" | |
| fi | |
| [[ -n "$candidate" ]] && { log "Found key in $src"; break; } | |
| done | |
| fi | |
| if [[ -z "$candidate" ]]; then | |
| for unit in "${BACKEND_UNITS[@]}"; do | |
| candidate="$(key_from_systemd_unit "$unit" 2>/dev/null || true)" | |
| [[ -n "$candidate" ]] && { log "Found key via systemd unit: $unit"; break; } | |
| done | |
| fi | |
| [[ -n "$candidate" ]] && UPSTREAM_API_KEY="$candidate" | |
| fi | |
| if [[ -z "${UPSTREAM_API_KEY:-}" ]]; then | |
| UPSTREAM_API_KEY="$DEFAULT_API_KEY" | |
| warn "No API key resolved; using placeholder ($DEFAULT_API_KEY)." | |
| fi | |
| export UPSTREAM_API_KEY UPSTREAM_URL LISTEN_PORT | |
| # =========================================================================== | |
| # 0b. Write the RUNTIME env file (systemd -> nginx). Key stored ONLY here. | |
| # =========================================================================== | |
| log "Writing runtime env to $RUNTIME_ENV (chmod 600)" | |
| ( umask 077 && cat > "$RUNTIME_ENV" <<EOF | |
| UPSTREAM_API_KEY=$UPSTREAM_API_KEY | |
| EOF | |
| ) | |
| chmod 600 "$RUNTIME_ENV" | |
| # --------------------------------------------------------------------------- | |
| # 1. Build dependencies (gettext-base => envsubst) | |
| # --------------------------------------------------------------------------- | |
| apt-get update | |
| apt-get install -y \ | |
| build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev \ | |
| libssl-dev wget curl gettext-base | |
| # --------------------------------------------------------------------------- | |
| # 2. Download and extract nginx | |
| # --------------------------------------------------------------------------- | |
| cd /tmp | |
| wget -q "http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" | |
| tar -xzf "nginx-${NGINX_VERSION}.tar.gz" | |
| cd "nginx-${NGINX_VERSION}" | |
| # --------------------------------------------------------------------------- | |
| # 3. Configure | |
| # --------------------------------------------------------------------------- | |
| ./configure \ | |
| --prefix="$INSTALL_PATH" \ | |
| --sbin-path="$INSTALL_PATH/sbin/nginx" \ | |
| --conf-path="$INSTALL_PATH/nginx.conf" \ | |
| --pid-path="$INSTALL_PATH/nginx.pid" \ | |
| --lock-path="$INSTALL_PATH/nginx.lock" \ | |
| --with-http_ssl_module \ | |
| --with-stream \ | |
| --with-http_realip_module \ | |
| --with-http_v2_module \ | |
| --with-threads \ | |
| --with-file-aio \ | |
| --with-http_stub_status_module | |
| # --------------------------------------------------------------------------- | |
| # 4. Build and install | |
| # --------------------------------------------------------------------------- | |
| make -j"$(nproc)" | |
| make install | |
| # --------------------------------------------------------------------------- | |
| # 5. systemd service — EnvironmentFile supplies the key at runtime | |
| # --------------------------------------------------------------------------- | |
| cat > "$SERVICE_FILE" <<EOL | |
| [Unit] | |
| Description=The NGINX HTTP and reverse proxy server | |
| After=network.target | |
| [Service] | |
| Type=forking | |
| PIDFile=${INSTALL_PATH}/nginx.pid | |
| EnvironmentFile=${RUNTIME_ENV} | |
| ExecStartPre=${INSTALL_PATH}/sbin/nginx -t | |
| ExecStart=${INSTALL_PATH}/sbin/nginx | |
| ExecReload=${INSTALL_PATH}/sbin/nginx -s reload | |
| ExecStop=${INSTALL_PATH}/sbin/nginx -s quit | |
| PrivateTmp=true | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOL | |
| # --------------------------------------------------------------------------- | |
| # 6. nginx.conf TEMPLATE. Note: the key is NOT interpolated here. | |
| # `env upstream_api_key;` exposes the var; $upstream_api_key is resolved | |
| # at request time from the master process environment. | |
| # --------------------------------------------------------------------------- | |
| cat > "$TEMPLATE_FILE" <<'EOL' | |
| worker_processes auto; | |
| # Expose the systemd-provided variable to nginx config. | |
| env upstream_api_key; | |
| events { worker_connections 1024; } | |
| http { | |
| # Map the environment variable into a normal nginx variable. | |
| map $upstream_api_key $api_key_value { | |
| default $upstream_api_key; | |
| } | |
| server { | |
| listen ${LISTEN_PORT}; | |
| server_name _; | |
| location /model-api/ { | |
| # Key injected at runtime; never present in this file. | |
| proxy_set_header Authorization "Bearer $api_key_value"; | |
| proxy_pass ${UPSTREAM_URL}; | |
| 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; | |
| proxy_set_header Connection ""; | |
| } | |
| } | |
| } | |
| EOL | |
| # --------------------------------------------------------------------------- | |
| # 7. Render. UPSTREAM_API_KEY is DELIBERATELY excluded from the whitelist. | |
| # --------------------------------------------------------------------------- | |
| ( umask 077 && \ | |
| envsubst '$LISTEN_PORT $UPSTREAM_URL' < "$TEMPLATE_FILE" > /tmp/nginx.conf ) | |
| install -m 644 -o root -g root /tmp/nginx.conf "$INSTALL_PATH/nginx.conf" | |
| rm -f "$TEMPLATE_FILE" /tmp/nginx.conf | |
| # --------------------------------------------------------------------------- | |
| # 8. Validate and start | |
| # --------------------------------------------------------------------------- | |
| "$INSTALL_PATH/sbin/nginx" -t | |
| if [[ "$UPSTREAM_API_KEY" == "$DEFAULT_API_KEY" ]]; then | |
| warn "Still using placeholder key; configure Vault, AWS, or a local source." | |
| else | |
| log "Key resolved and stored only in $RUNTIME_ENV (chmod 600)." | |
| log "nginx.conf contains no secret and is world-readable (644) on purpose." | |
| fi | |
| log "NGINX install complete (key kept off disk in nginx.conf)." | |