Can't get the API to work

I was following this:

This isn’t working:

curl -k -X POST "``https://pi.hole/api/auth``" --data '{"password":"your-password"}'

I expect this output:

{
"session": {
"valid": true,
"totp": false,
"sid": "vFA+EP4MQ5JJvJg+3Q2Jnw=",
"csrf": "Ux87YTIiMOf/GKCefVIOMw=",
"validity": 300
},
"took": 0.0002
}

But I get this instead:

curl: (7) Failed to connect to pi.hole port 443 after 1 ms: Could not connect to server

And if I try the http only method:

curl -k -X POST "https://pi.hole/api/auth" --data '{"password":"your-password"}'

I get this:

404 Not Found

404 Not Found

So, I don’t know how to make this API work.

Please upload a debug log and post just the token URL that is generated after the log is uploaded by running the following command from the Pi-hole host terminal:

sudo pihole -d

or if you run your Pi-hole as a Docker container:

docker exec -it <pihole-container-name-or-id> pihole -d

where you substitute <pihole-container-name-or-id> as required.

Here: https://tricorder.pi-hole.net/U19DlI9A/

You are trying to connect to the web interface using the default https port (443), but your Pi-hole is using port 8443:

*** [ DIAGNOSING ]: Ports in use
    (...)
[✓] tcp:0.0.0.0:8443 is in use by pihole-FTL

Also, lighttpd is using port 80:

*** [ DIAGNOSING ]: Ports in use
    (...)
[✗] tcp:0.0.0.0:80 is in use by lighttpd

Pi-hole v6 doesn't use lighttpd.
If you are not using it for other services, you can safely disable/uninstall it.


Solutions:

  1. the simplest way to use the API, without changing any configuration, is to use this URL:
    https://pi.hole:8443/api/auth

  2. If you don't need lighttpd, uninstall it and change Pi-hole ports using this command:

    sudo pihole-FTL --config webserver.port '80o,443os'
    

    Then use one of these URLs:
    https://pi.hole/api/auth or http://pi.hole/api/auth

This worked:

curl -k -X POST "``https://pi.hole:8443/api/auth``" --data '{"password":"your-password"}'

I was able to get my network monitor script to work again on my netbook with a 32 bit only CPU.

I was using PIHOLE_URL="http://192.168.1.254"

Now the script is using PIHOLE_URL="https://pi.hole:8443"

And I refactored the script. But I would be happy if there aren’t a ton of changes.

Please tell me there won’t be anymore huge changes with the API in the future.

As I explained, you can fix the settings to use whatever you want.

If you want to use http://192.168.1.254, you just need to disable lighttpd and change Pi-hole port using sudo pihole-FTL --config webserver.port '80o,443os'.

After that, you will be able to use any of these URLs:

Eh… It’s done now. I got the script refactored to show what I want and changed it to use https instead of http.

I spent a couple of hours refactoring the script with the aid of chatgpt (as I suck at coding, and it’s not really my thing). The end result works. So, I’m not going to mess with it now. The thing is, my script worked before. So, what broke it?

This is my newly refactored script:

#!/bin/bash

==========================

Pi-hole Authentication & Stats Monitor

==========================

Configuration

INTERVAL=5                 # Network refresh interval (seconds)
SID_EXPIRY=2592000         # SID validity (30 days)
LAN_TARGET="192.168.1.1"   # Router IP
WAN_TARGET="1.1.1.1"       # Cloudflare DNS
PIHOLE_URL="https://pi.hole:8443"  # Pi-hole URL
PIHOLE_PASS_FILE="$HOME/.pihole_auth"

Colors

GREEN="\e[32m"
RED="\e[31m"
YELLOW="\e[33m"
BOLD="\e[1m"
RESET="\e[0m"

Load password

if [[ -f "$PIHOLE_PASS_FILE" ]]; then
PIHOLE_PASS=$(<"$PIHOLE_PASS_FILE")
else
echo -e "${RED}Pi-hole password file not found!${RESET}"
exit 1
fi

Globals

SID=""
CSRF=""
LAST_SID_TIME=0

Get a new SID + CSRF token

get_sid() {
local resp
resp=$(curl -ks -X POST "$PIHOLE_URL/api/auth" 
-H "Content-Type: application/json" 
-d "{"password":"$PIHOLE_PASS"}")

SID=$(echo "$resp" | jq -r '.session.sid')
CSRF=$(echo "$resp" | jq -r '.session.csrf')

if [[ -z "$SID" || -z "$CSRF" ]]; then
    echo -e "${RED}${BOLD}Failed to get SID from Pi-hole.${RESET}"
    return 1
fi
return 0

}

Fetch stats

get_stats() {
local stats
stats=$(curl -ks -H "Cookie: sid=$SID" -H "X-CSRF-Token: $CSRF" 
"$PIHOLE_URL/api/stats/summary")

if [[ -z "$stats" ]]; then
    echo -e "${RED}Failed to fetch Pi-hole stats.${RESET}"
    return 1
fi

total=$(echo "$stats" | jq -r '.queries.total')
blocked=$(echo "$stats" | jq -r '.queries.blocked')
percent=$(echo "$stats" | jq -r '.queries.percent_blocked')

echo -e "${BOLD}${GREEN}=== Pi-hole Stats ===${RESET}"
echo -e "${BOLD}Total Queries:${RESET} $total"
echo -e "${BOLD}Blocked Queries:${RESET} $blocked"
echo -e "${BOLD}Percentage Blocked:${RESET} $percent%"

}

Fetch recent queries

get_recent_queries() {
local queries
queries=$(curl -ks -H "Cookie: sid=$SID" -H "X-CSRF-Token: $CSRF" 
"$PIHOLE_URL/api/queries")

if [[ -z "$queries" ]]; then
    echo -e "${RED}Failed to fetch recent queries.${RESET}"
    return 1
fi

echo -e "${BOLD}${GREEN}=== Recent Queries ===${RESET}"

# Extract newest queries first, 10 most recent
echo "$queries" | jq -r '
    .queries 
    | sort_by(.id) 
    | reverse 
    | .[] 
    | "\(.domain) \(.status) \(.client.ip)"' \
    | head -n 10 \
    | while read domain status client_ip; do
        case "$status" in
            FORWARDED) echo -e "$domain ($status) [$client_ip]" ;;
            CACHE) echo -e "$domain (${YELLOW}$status${RESET}) [$client_ip]" ;;
            CACHE_STALE) echo -e "$domain (${YELLOW}$status${RESET}) [$client_ip]" ;;
            *) echo -e "$domain (${RED}$status${RESET}) [$client_ip]" ;;
        esac
    done

}

LAN/WAN checks

check_lan() {
if ping -c1 -W1 "$LAN_TARGET" &>/dev/null; then
echo -e "${BOLD}LAN:${RESET} ${GREEN}UP${RESET}"
else
echo -e "${BOLD}LAN:${RESET} ${RED}DOWN${RESET}"
fi
}

check_wan() {
if ping -c1 -W1 "$WAN_TARGET" &>/dev/null; then
echo -e "${BOLD}WAN:${RESET} ${GREEN}UP${RESET}"
else
echo -e "${BOLD}WAN:${RESET} ${RED}DOWN${RESET}"
fi
}

Recently blocked domains

get_recent_blocked() {
local blocked
blocked=$(curl -ks -H "Cookie: sid=$SID" -H "X-CSRF-Token: $CSRF" 
"$PIHOLE_URL/api/stats/recent_blocked")

if [[ -z "$blocked" ]]; then
    echo -e "${RED}Failed to fetch blocked domains.${RESET}"
    return 1
fi

echo -e "${BOLD}${GREEN}=== Recently Blocked Domains ===${RESET}"
echo "$blocked" | jq -r '.blocked[]' | sort | uniq -c | sort -nr | head -n 10 \
    | awk '{print $2 ": " $1}'

}

Main loop

while true; do
clear
echo -e "${BOLD}=== Network & Pi-hole Monitor ===${RESET}"
echo -e "${BOLD}Press Ctrl+C to exit${RESET}\n"

check_lan
check_wan
echo

# Refresh SID if expired
now=$(date +%s)
if [[ -z "$SID" || $((now - LAST_SID_TIME)) -ge $SID_EXPIRY ]]; then
    echo -e "${YELLOW}Refreshing Pi-hole SID...${RESET}"
    if get_sid; then
        LAST_SID_TIME=$now
    else
        echo -e "${RED}Skipping stats fetch.${RESET}"
    fi
fi

get_stats || echo -e "${RED}Stats fetch failed this round.${RESET}"
get_recent_queries || echo -e "${RED}Queried domains fetch failed.${RESET}"
get_recent_blocked || echo -e "${RED}Recently blocked fetch failed.${RESET}"

sleep "$INTERVAL"

done

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.