Skip to content

Commit 430ede0

Browse files
committed
Fix host enable/disable functionality - Use NPM native endpoints
- Fixed critical bug where --host-disable showed 'disabled' in UI but sites remained accessible - Replaced generic PUT /api/nginx/proxy-hosts/{id} approach with NPM's dedicated endpoints: • POST /api/nginx/proxy-hosts/{id}/enable for enabling hosts • POST /api/nginx/proxy-hosts/{id}/disable for disabling hosts - Discovered through browser dev tools inspection of NPM web interface requests - Added comprehensive documentation explaining the bug discovery process - Removed debug output messages for cleaner user experience The generic JSON modification approach only updates the UI status but doesn't actually disable network access. NPM's native endpoints properly handle the nginx configuration changes required for actual functionality. Resolves: GitHub issue #3
1 parent 5c14357 commit 430ede0

File tree

1 file changed

+64
-36
lines changed

1 file changed

+64
-36
lines changed

npm-api.sh

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ cert_show() {
13401340
if [ -z "$DOMAIN_CERTS" ]; then
13411341
echo -e " ℹ️ ${COLOR_YELLOW}No certificates found for domain: $search_term${CoR}"
13421342
else
1343-
echo "$DOMAIN_CERTS" | jq -r '" 🔒 ID: \(.id)\n • Domain(s): \(.domain_names | join(", "))\n • Provider : \(.provider)\n • Created on: \(.created_on // "N/A")\n • Expires on: \(.expires_on // "N/A")\n • Status: \(if .expired then "❌ EXPIRED" else if .expires_on then "✅ VALID" else "⚠️ PENDING" end end)"' | while IFS= read -r line; do if [[ $line == *"❌ EXPIRED"* ]]; then echo -e "${line/❌ EXPIRED/${COLOR_RED}❌ EXPIRED${CoR}}"; elif [[ $line == *"✅ VALID"* ]]; then echo -e "${line/✅ VALID/${COLOR_GREEN}✅ VALID${CoR}}"; elif [[ $line == *"⚠️ PENDING"* ]]; then echo -e "${line/⚠️ PENDING/${COLOR_YELLOW}⚠️ PENDING${CoR}}"; else echo -e "$line"; fi; done
1343+
echo "$DOMAIN_CERTS" | jq -r '" 🔒 ID: \(.id)\n • Domain(s): \(.domain_names | join(", "))\n • Provider: \(.provider)\n • Created on: \(.created_on // "N/A")\n • Expires on: \(.expires_on // "N/A")\n • Status: \(if .expired then "❌ EXPIRED" else if .expires_on then "✅ VALID" else "⚠️ PENDING" end end)"' | while IFS= read -r line; do if [[ $line == *"❌ EXPIRED"* ]]; then echo -e "${line/❌ EXPIRED/${COLOR_RED}❌ EXPIRED${CoR}}"; elif [[ $line == *"✅ VALID"* ]]; then echo -e "${line/✅ VALID/${COLOR_GREEN}✅ VALID${CoR}}"; elif [[ $line == *"⚠️ PENDING"* ]]; then echo -e "${line/⚠️ PENDING/${COLOR_YELLOW}⚠️ PENDING${CoR}}"; else echo -e "$line"; fi; done
13441344
echo ""
13451345
fi
13461346
}
@@ -1934,6 +1934,21 @@ host_search() {
19341934
}
19351935

19361936
################################
1937+
################################
1938+
# Enable a proxy host by ID
1939+
#
1940+
# 💡 NPM-specific endpoint discovery (2025-05-30):
1941+
# ================================================
1942+
# Like host_disable(), this function uses NPM's dedicated endpoint:
1943+
#
1944+
# ✅ CORRECT approach:
1945+
# POST /api/nginx/proxy-hosts/{id}/enable with empty body
1946+
# → Actually enables the site and makes it accessible
1947+
#
1948+
# ❌ The generic PUT approach with JSON modification doesn't work reliably.
1949+
# Reference: Same discovery as host_disable() function above.
1950+
################################
1951+
19371952
# Enable a proxy host by ID
19381953
host_enable() {
19391954
local host_id="$1"
@@ -1946,34 +1961,31 @@ host_enable() {
19461961
fi
19471962

19481963
check_token_notverbose
1949-
19501964

1951-
# Check if the proxy host exists and get its current configuration
1965+
# Check if the proxy host exists first
19521966
CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
19531967
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
19541968

19551969
if [ $? -eq 0 ] && [ -n "$CHECK_RESPONSE" ]; then
1970+
# Check if the host was found (not a 404 error)
1971+
if echo "$CHECK_RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
1972+
echo -e "${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
1973+
return 1
1974+
fi
1975+
19561976
# Get domain name for display
19571977
DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
19581978

1959-
# Create minimal payload with only the enabled property
1960-
PAYLOAD='{"enabled":true}'
1979+
echo -e "\n ${COLOR_YELLOW}🔄 Enabling proxy host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
19611980

1962-
# Send PUT request with minimal payload
1963-
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$host_id" \
1981+
# Use the CORRECT NPM endpoint: POST to /enable (like the web interface does)
1982+
RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/proxy-hosts/$host_id/enable" \
19641983
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
1965-
-H "Content-Type: application/json" \
1966-
-d "$PAYLOAD")
1984+
-H "Content-Type: application/json; charset=UTF-8")
19671985

19681986
if [ $? -eq 0 ] && ! echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
1969-
if [ "$DOMAIN_NAME" != "null" ] && [ -n "$DOMAIN_NAME" ]; then
1970-
1971-
echo -e "\n ${COLOR_YELLOW}🔄 Enabling proxy host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
1972-
echo -e "${COLOR_GREEN}Successfully enabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}\n"
1973-
1974-
else
1975-
echo -e " ℹ️ ${COLOR_YELLOW}No domain name associated with this host${CoR}"
1976-
fi
1987+
echo -e "${COLOR_GREEN}Successfully enabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
1988+
# echo -e " 🎯 ${COLOR_GREEN}Using NPM's native enable endpoint${CoR}\n"
19771989
else
19781990
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
19791991
echo -e "${COLOR_RED}Failed to enable proxy host: $ERROR_MSG${CoR}"
@@ -1985,49 +1997,65 @@ host_enable() {
19851997

19861998
################################
19871999
# Disable a proxy host by ID
2000+
#
2001+
# 🐛 IMPORTANT BUG DISCOVERY (2025-05-30):
2002+
# ==========================================
2003+
# The NPM web interface uses a DIFFERENT endpoint than expected!
2004+
#
2005+
# ❌ WRONG approach (what we tried before):
2006+
# PUT /api/nginx/proxy-hosts/{id} with modified JSON (enabled: false)
2007+
# → Shows "disabled" in interface but site remains ACCESSIBLE!
2008+
#
2009+
# ✅ CORRECT approach (what NPM web interface actually uses):
2010+
# POST /api/nginx/proxy-hosts/{id}/disable with empty body
2011+
# → Actually disables the site and makes it INACCESSIBLE!
2012+
#
2013+
# This was discovered by inspecting NPM web interface network traffic.
2014+
# NPM has dedicated /enable and /disable endpoints that work properly.
2015+
# Reference: GitHub issue #3 (nginx-proxy-manager-Bash-API)
2016+
################################
19882017
host_disable() {
19892018
local host_id="$1"
19902019

19912020
if [ -z "$host_id" ]; then
19922021
echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-disable option requires a host 🆔.${CoR}"
1993-
echo -e " Usage : ${COLOR_ORANGE}$0 --host-disable <host_id>${CoR}"
1994-
echo -e " Example: ${COLOR_GREEN}$0 --host-disable 42${CoR}"
2022+
echo -e " Usage : ${COLOR_ORANGE}$0 --host-disable <host_id>${CoR}"
2023+
echo -e " Example: ${COLOR_GREEN}$0 --host-disable 42${CoR}"
19952024
return 1
19962025
fi
19972026

19982027
check_token_notverbose
19992028

2000-
# Check if the proxy host exists and get its current configuration
2029+
# Check if the proxy host exists first
20012030
CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
20022031
-H "Authorization: Bearer $(cat "$TOKEN_FILE")")
20032032

20042033
if [ $? -eq 0 ] && [ -n "$CHECK_RESPONSE" ]; then
2034+
# Check if the host was found (not a 404 error)
2035+
if echo "$CHECK_RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
2036+
echo -e "${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
2037+
return 1
2038+
fi
2039+
20052040
# Get domain name for display
20062041
DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
20072042

2008-
# Create minimal payload with only the enabled property
2009-
PAYLOAD='{"enabled":false}'
2043+
echo -e "\n ${COLOR_YELLOW}🔄 Disabling proxy host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
20102044

2011-
# Send PUT request with minimal payload
2012-
RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$host_id" \
2045+
# Use the CORRECT NPM endpoint: POST to /disable (like the web interface does)
2046+
RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/proxy-hosts/$host_id/disable" \
20132047
-H "Authorization: Bearer $(cat "$TOKEN_FILE")" \
2014-
-H "Content-Type: application/json" \
2015-
-d "$PAYLOAD")
2048+
-H "Content-Type: application/json; charset=UTF-8")
20162049

20172050
if [ $? -eq 0 ] && ! echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
2018-
2019-
if [ "$DOMAIN_NAME" != "null" ] && [ -n "$DOMAIN_NAME" ]; then
2020-
echo -e "\n ${COLOR_YELLOW}🔄 Disabling proxy host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
2021-
echo -e "${COLOR_GREEN}Successfully disabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}\n"
2022-
else
2023-
echo -e " ℹ️ ${COLOR_YELLOW}No domain name associated with this host${CoR}\n"
2024-
fi
2051+
echo -e "${COLOR_GREEN}Successfully disabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
2052+
# echo -e " 🎯 ${COLOR_GREEN}Using NPM's native disable endpoint${CoR}\n"
20252053
else
20262054
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
2027-
echo -e "${COLOR_RED}Failed to disable proxy host: $ERROR_MSG${CoR}\n"
2055+
echo -e "${COLOR_RED}Failed to disable proxy host: $ERROR_MSG${CoR}"
20282056
fi
20292057
else
2030-
echo -e "${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}\n"
2058+
echo -e "${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
20312059
fi
20322060
}
20332061

@@ -2150,7 +2178,7 @@ host_acl_enable() {
21502178
host_acl_disable() {
21512179
if [ -z "$HOST_ID" ]; then
21522180
echo -e "\n ⛔ ${COLOR_RED}Error: HOST_ID is required to disable the ACL.${CoR}"
2153-
echo -e " Usage: $0 --host-acl-disable <host_id>"
2181+
echo -e " Usage: $0 --host-acl-disable <host_id>\n"
21542182
exit 1
21552183
fi
21562184
check_token_notverbose

0 commit comments

Comments
 (0)