-
-
Notifications
You must be signed in to change notification settings - Fork 20
Add reverse proxy support #38
Copy link
Copy link
Open
Labels
Description
I tried to configure a reverse proxy so that requests coming to https://domain.name/ipc/camera_name/* are redirected to http://camera_ip/*. But there was a problem: majestic-webui does not support processing of X-Forwarded-* headers from a reverse proxy, and does not support the X-Forwarded-Prefix header. Incorrect links relative to the site root are formed in the response.
Example of nginx reverse proxy configuration:
server {
listen 443 ssl;
server_name domain.name;
ssl_certificate /path/to/cert.crt;
ssl_certificate_key /path/to/cert.key;
location ^~ /ipc/cam24/ {
rewrite ^/ipc/cam24/(.*)$ /$1 break;
proxy_pass http://192.168.1.24/;
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 X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Prefix /ipc/cam24;
}
}
Example of how to process X-Forwarded-* headers:
reverse_proxy.cgi
#!/usr/bin/haserl
<%
TRUSTED_PROXIES="127.0.0.1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16"
is_ipv6() {
case "$1" in
*:*) return 0 ;;
*) return 1 ;;
esac
}
ip_to_decimal() {
IFS=. read -r a b c d <<< "$1"
echo $(( (a << 24) + (b << 16) + (c << 8) + d ))
}
ip_in_cidr() {
ip="$1"
cidr="$2"
IFS=/ read network mask <<< "$cidr"
ip_decimal=$(ip_to_decimal "$ip")
network_decimal=$(ip_to_decimal "$network")
mask_decimal=$((0xFFFFFFFF << (32 - mask)))
if [ $((ip_decimal & mask_decimal)) -eq $((network_decimal & mask_decimal)) ]; then
return 0
else
return 1
fi
}
is_trusted_ip() {
for proxy in $TRUSTED_PROXIES; do
if echo "$proxy" | grep -q '/'; then
if ip_in_cidr "$1" "$proxy"; then
return 0
fi
else
if [ "$1" = "$proxy" ]; then
return 0
fi
fi
done
return 1
}
get_real_client_ip() {
forwarded="$1"
IFS=',' read -ra ips <<< "$forwarded"
for i in "${!ips[@]}"; do
ips[$i]="$(echo "${ips[$i]}" | xargs)"
done
real_ip=""
for (( idx=${#ips[@]}-1 ; idx>=0 ; idx-- )); do
ip="${ips[$idx]}"
if is_trusted_ip "$ip"; then
continue
else
real_ip="$ip"
break
fi
done
if [ -z "$real_ip" ] && [ "${#ips[@]}" -gt 0 ]; then
real_ip="${ips[0]}"
fi
echo "$real_ip"
}
ORIGINAL_REMOTE_ADDR="$REMOTE_ADDR"
USE_X_FORWARDED=0
if ! is_ipv6 "$REMOTE_ADDR"; then
if is_trusted_ip "$REMOTE_ADDR"; then
USE_X_FORWARDED=1
fi
fi
if [ "$USE_X_FORWARDED" -eq 1 ] && [ -n "$HTTP_X_FORWARDED_FOR" ]; then
REMOTE_ADDR="$(get_real_client_ip "$HTTP_X_FORWARDED_FOR")"
fi
PROTO="http"
if [ -n "$HTTP_X_FORWARDED_PROTO" ]; then
PROTO="$HTTP_X_FORWARDED_PROTO"
fi
HOST="$SERVER_NAME"
if [ -n "$HTTP_X_FORWARDED_HOST" ]; then
HOST="$HTTP_X_FORWARDED_HOST"
fi
PORT="$SERVER_PORT"
if [ -n "$HTTP_X_FORWARDED_PORT" ]; then
PORT="$HTTP_X_FORWARDED_PORT"
fi
PREFIX=""
if [ -n "$HTTP_X_FORWARDED_PREFIX" ]; then
PREFIX="$HTTP_X_FORWARDED_PREFIX"
fi
if [ -n "$PREFIX" ] && [ "${PREFIX:0:1}" != "/" ]; then
PREFIX="/$PREFIX"
fi
BASE_URL="${PROTO}://${HOST}"
if { [ "$PROTO" = "http" ] && [ "$PORT" != "80" ]; } || { [ "$PROTO" = "https" ] && [ "$PORT" != "443" ]; }; then
BASE_URL="${BASE_URL}:${PORT}"
fi
BASE_URL="${BASE_URL}${PREFIX}"
echo "REMOTE_ADDR=$REMOTE_ADDR"
echo "PROTO=$PROTO"
echo "HOST=$HOST"
echo "PORT=$PORT"
echo "PREFIX=$PREFIX"
echo "BASE_URL=$BASE_URL"
%>test.cgi
#!/usr/bin/haserl
<%in reverse_proxy.cgi %>
<!DOCTYPE html>
<html lang="en" data-bs-theme="<%= ${webui_theme:=dark} %>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><% html_title %></title>
<link rel="stylesheet" href="<%= PREFIX %>a/bootstrap.min.css">
<link rel="stylesheet" href="<%= PREFIX %>a/bootstrap.override.css">
<script src="<%= PREFIX %>a/bootstrap.bundle.min.js"></script>
<script src="<%= PREFIX %>a/main.js"></script>
</head>
<body>
<p>Remote Address: <%= REMOTE_ADDR %></p>
<p>Protocol: <%= PROTO %></p>
<p>Host: <%= HOST %></p>
<p>Port: <%= PORT %></p>
<p>Prefix: <%= PREFIX %></p>
<p>Base URL: <%= BASE_URL %></p>
<p>Link: <a href="<%= PREFIX %>mjpeg">Click here</a></p>
</body>Reactions are currently unavailable