cvat-ai / cvat

Annotate better with CVAT, the industry-leading data engine for machine learning. Used and trusted by teams at any scale, for data of any scale.
https://cvat.ai
MIT License
12.75k stars 3.03k forks source link

Running CVAT in http behind a https nginx proxy #7288

Open darrenchang opened 11 months ago

darrenchang commented 11 months ago

Actions before raising this issue

Steps to Reproduce

  1. Start up cvat in http mode
  2. Put it behind a https nginx proxy
  3. Use the proxy servers ip to access the cvat server
    1. Create a project
    2. Create a task (It will fail because the ui will try to call http:// instead of https://)

Screenshot from 2023-12-22 15-43-29

Expected Behavior

No response

Possible Solution

No response

Context

No response

Environment

- Cvat v2.9.2
yanjunli76 commented 11 months ago

It works for me if I set CVAT_HOST=localhost

darrenchang commented 11 months ago

It works for me if I set CVAT_HOST=localhost

What im doing is adding a proxy server between the client and the cvat server.

Client --https--> proxy --http--> Cvat

And my CVAT_HOST is set to my proxy's IP. It works for the most part, but some api requests do not use the https protocol. I guess the problem is in cvat_ui.

yanjunli76 commented 11 months ago

It works for me if I set CVAT_HOST=localhost

What im doing is adding a proxy server between the client and the cvat server.

Client --https--> proxy --http--> Cvat

And my CVAT_HOST is set to my proxy's IP. It works for the most part, but some api requests do not use the https protocol. I guess the problem is in cvat_ui.

The deployment is same as mine. for proxy, I use Nginx.

I have the same issue as you described when I set CVAT_HOST to my domain name. But the following configs work for me.

For nginx config:

server {
    server_name xxxx;
    client_max_body_size 900M;
    location / {
    proxy_pass http://localhost:8080/;
    proxy_buffering off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate xxxxxx; # managed by Certbot
    ssl_certificate_key xxxxxx; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = xxxxxx) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name xxxxxx;
    return 404; # managed by Certbot
}

the command to run cvat:

CVAT_HOST=localhost docker compose -f docker-compose.yml -f components/serverless/docker-compose.serverless.yml up -d --force-recreate
darrenchang commented 11 months ago

It works for me if I set CVAT_HOST=localhost

What im doing is adding a proxy server between the client and the cvat server. Client --https--> proxy --http--> Cvat And my CVAT_HOST is set to my proxy's IP. It works for the most part, but some api requests do not use the https protocol. I guess the problem is in cvat_ui.

The deployment is same as mine. for proxy, I use Nginx.

I have the same issue as you described when I set CVAT_HOST to my domain name. But the following configs work for me.

For nginx config:

server {
    server_name xxxx;
    client_max_body_size 900M;
    location / {
  proxy_pass http://localhost:8080/;
      proxy_buffering off;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Port $server_port;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate xxxxxx; # managed by Certbot
    ssl_certificate_key xxxxxx; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = xxxxxx) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name xxxxxx;
    return 404; # managed by Certbot
}

the command to run cvat:

CVAT_HOST=localhost docker compose -f docker-compose.yml -f components/serverless/docker-compose.serverless.yml up -d --force-recreate

Thank you for sharing your nginx config. I'll try it out when I get a chance. I'm using https://github.com/NginxProxyManager/nginx-proxy-manager as my proxy. Maybe it's not forwarding my protocol correctly.

nginx proxy manager version: v2.10.4

darrenchang commented 11 months ago

It works for me if I set CVAT_HOST=localhost

What im doing is adding a proxy server between the client and the cvat server. Client --https--> proxy --http--> Cvat And my CVAT_HOST is set to my proxy's IP. It works for the most part, but some api requests do not use the https protocol. I guess the problem is in cvat_ui.

The deployment is same as mine. for proxy, I use Nginx.

I have the same issue as you described when I set CVAT_HOST to my domain name. But the following configs work for me.

For nginx config:

server {
    server_name xxxx;
    client_max_body_size 900M;
    location / {
  proxy_pass http://localhost:8080/;
      proxy_buffering off;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Port $server_port;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate xxxxxx; # managed by Certbot
    ssl_certificate_key xxxxxx; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = xxxxxx) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name xxxxxx;
    return 404; # managed by Certbot
}

the command to run cvat:

CVAT_HOST=localhost docker compose -f docker-compose.yml -f components/serverless/docker-compose.serverless.yml up -d --force-recreate

The nginx config didn't work for me. It looks like cvat is using tusd for upload (import datasets). https://github.com/tus/tusd

I have my cvat hosted on A machine with CVAT_HOST=localhost On my proxy_machine I have the below config

server {
    server_name proxy_machine;
    listen       443 ssl http2;
    listen  [::]:443 ssl http2;
    ssl_certificate     test.crt;
    ssl_certificate_key test.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
    ssl_ecdh_curve prime256v1;
    ssl_session_cache shared:SSL:5m;
    ssl_session_timeout 24h;
    ssl_session_tickets off;
    ssl_buffer_size 4k;
    server_name  localhost;
    client_max_body_size 100M;
    client_body_buffer_size 100M;
    keepalive_timeout 10;
    large_client_header_buffers 8 32k;
    proxy_max_temp_file_size 0;
    proxy_read_timeout 300;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    proxy_headers_hash_max_size 512;
     proxy_headers_hash_bucket_size 128;
    keepalive_requests 1000;

    location / {
        # root /usr/share/nginx/html/gui;
        # index index.html index.htm;
        # try_files $uri $uri/ /index.html;
        proxy_pass http://cvat_host_ip:8080/;
        proxy_set_header Host localhost;
        # proxy_buffering off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /favicon.ico {
        alias /usr/share/nginx/html/favicon.ico;
    }
}

The error I get when I try to import dataset image

darrenchang commented 11 months ago

I think I've found the issue.

https://github.com/opencv/cvat/blob/c5852094560c7557511df31deb41f192e2fd7d9d/cvat/apps/engine/mixins.py#L286

If I have a reverse proxy listening on https that passes requests to my cvat server running on http, Django would return the http url, which is incorrect.

The line should probably use the scheme of the request's HTTP_ORIGIN instead of django's scheme.

location = request.build_absolute_uri() #http://somehost:8080/...
# TODO somehow replace the scheme to the correctly one