ZoneMinder / zoneminder

ZoneMinder is a free, open source Closed-circuit television software application developed for Linux which supports IP, USB and Analog cameras.
http://www.zoneminder.com/
GNU General Public License v2.0
5.04k stars 1.22k forks source link

Web resources should be accessed using relative path #3761

Open jdeus opened 1 year ago

jdeus commented 1 year ago

Describe Your Environment

Describe the bug All web elements should be requested using a relative path, as described by ZM_BASE_URL. However, when setup using a reverse proxy on /services/zoneminder, it's appartent that a lot of resources are requested using an absolute path and breaks a lot of features :

rp-nginx/nginx.conf :

server { 
 listen 80;
 server_name rp-nginx;

 location /services/zoneminder {
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header Host $http_host;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   rewrite ^/services/zoneminder(.*) /$1 break;
   proxy_pass http://zoneminder-app:80;
   proxy_redirect off;
 }
}

docker-compose.yml

services:
  # https://github.com/zoneminder-containers/zoneminder-base
  # mkdir -p zoneminder-db/data zoneminder-app/{data,config,log}
  # chown -R 911:911 zoneminder-*
  zoneminder-db:
    image: mariadb:11.1.2
    stop_grace_period: 60s
    networks:
      - zoneminder
    user: "911:911"
    volumes:
      - ./zoneminder-db/data:/var/lib/mysql
    environment:
      # Don't change the database name, this is not supported by the zoneminder's dockerfile startup script yet
      MARIADB_DATABASE: zm
      MARIADB_ROOT_PASSWORD: abcdef
      MARIADB_USER: zoneminder
      MARIADB_PASSWORD: abcdef
  zoneminder-app:
    image: ghcr.io/zoneminder-containers/zoneminder-base:1.36.33
    stop_grace_period: 60s
    depends_on:
      - zoneminder-db
    networks:
      - zoneminder
      - rp-nginx
    volumes:
      - ./zoneminder-app/data:/data
      - ./zoneminder-app/config:/config
      - ./zoneminder-app/log:/log
      - type: tmpfs
        target: /dev/shm
        tmpfs:
          size: 1000000000
    environment:
      TZ: "Europe/Paris"
      MYSQL_HOST: zoneminder-db
      MYSQL_USER: zoneminder
      MYSQL_PASSWORD: abcdef
  # chown -R 1001:1001 rp-nginx
  rp-nginx:
    image: nginxinc/nginx-unprivileged:1.25.2
    user: "1001:1001"
    ports:
      - "80:80"
    depends_on:
      - zoneminder-db
      - zoneminder-app
    volumes:
      - ./rp-nginx/nginx.conf:/etc/nginx/nginx.conf
      - nginx-cache:/var/cache/nginx
    networks:
      - rp-nginx
volumes:
  nginx-cache:
    name: nginx-cache
networks:
  rp-nginx:
  zoneminder:
welcome[bot] commented 1 year ago

Thanks for opening your first issue here! Just a reminder, this forum is for Bug Reports only. Be sure to follow the issue template!

netikras commented 1 year ago

I can second that. I've read in previous issues that ZM_BASE_URL is deprecated, but the idea is sound.

I also tried injecting a tag, but that didn't help

sub_filter       '</head>' '<base href="/my/cams/admin"></head>';

In the browser's js console, I still see lots of red 404 entries.

I also tried setting HTTP headers that, according to spec, are supposed to suggest base URI. Apparently, both and these headers are completely ignored by ZM.

proxy_set_header Content-Location /my/cams/admin;
proxy_set_header Content-Base /my/cams/admin;

We do need a mechanism to reliably hide ZM behind a reverse proxy. Preferably, this mechanism should use either relative URLs or standard absolute URL prefixing mechnisms ( or Content-Base header).

Unfortunately, I'm not a PHP dev and can't contribute much.

netikras commented 1 year ago

Another probably related issue: some URLs are stepping one level up. Say, if my actual base URL is /my/cams/admin, some resources are being fetched from /my/cams (losing the /admin part of the URL).

netikras commented 1 year ago

A temporary somewhat working workaround:

   location ~ ^/my/cams/admin/?(.*) {
    proxy_pass       http://localhost:81/$1$is_args$args;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    sub_filter       'src="/' 'src="'; 
    sub_filter       'href="/' 'href="';
    sub_filter       '/index.php' 'index.php';
    sub_filter_once  off;
  } 
  location ~ ^/my/cams/?(.*) {
    proxy_pass       http://localhost:81/$1$is_args$args;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    sub_filter       'src="/' 'src="';
    sub_filter       'href="/' 'href="';
    sub_filter       '/index.php' 'index.php';
    sub_filter_once  off;

  } 

Still, snapshot thumbnails are attempted to fetch from an absolute /index.php. Android app is having trouble automatically detecting cgi-bin (had to specify the path manually; still doesn't load monitors). Prolly something else is broken as well.

At least I can view the stream in the web browser now.

Still, this has to be fixed.

connortechnology commented 1 year ago

I run ZM behind reverse proxies all the time.... with and with the /zm.... havn't done a more complex url change.

The issue is further complicated by multi-server. Wherever we are using an absolute url, we are likely dealing with a multi-server case.

netikras commented 1 year ago

@connortechnology

  1. which version?
  2. can you show us, what's the Live Stream page, what's the cgi-bin URL in the HTML opened in your browser? (no need or the whole URL -- just the beginning; whether slash is there or not) [here's mine for example image
  3. In the same page, what's the URL of the index.php (browser's devtools → network tab; I'm interested in what's the base URL) image
  4. Have you done any base-url-related configuration server-side?
SteveGilvarry commented 4 days ago

@connortechnology want to answer this so we can close it or add to list for 1.38?

connortechnology commented 4 days ago

I think we need to add it to the list.

I'm not sure about img url's... but the redirects for login and privacy use ZM_BASE_URL and I don't see why. Unfortunately I don't think we can get this in for 1.36.35 but I think we can certainly do away with BASE_URL entirely.

connortechnology commented 4 days ago

Actually it's a pretty small change... maybe it could go in 1.36.35.