rr- / szurubooru

Image board engine, Danbooru-style.
GNU General Public License v3.0
664 stars 175 forks source link

[Windows10] setting up nginx reverse proxy with basic_auth breaks the server #611

Open SpaghettiMonkey opened 8 months ago

SpaghettiMonkey commented 8 months ago

For some context, my container is running from a drive connected via USB while my nginx instance is on my main drive, but this doesn't seem to pose any problem atm. I have set up a nginx reverse proxy on my host machine listening to port 80 and passing to localhost 8080. I have done it according to the recommendations (4-preparing for production in INSTALL.md), with some tweaks as it didn't seem to work right off the box. I ended up with this nginx.conf :

worker_processes  1;
events {
    worker_connections  1024;
}

http{
server_names_hash_bucket_size 64;
include       mime.types;

# ideally, use ssl termination + cdn with a provider such as cloudflare.
# modify as needed!

# rate limiting zone
# poor man's ddos protection, essentially
limit_req_zone $binary_remote_addr zone=throttle:10m rate=25r/s;

# www -> non-www
#server {
  #listen 80;
  #listen [::]:80;
  #server_tokens off;
  #server_name www.testing.com
  #return 301 http://testing.com$request_uri;
#}

server {
  server_name localhost;
  client_max_body_size 100M;
  client_body_timeout 30s;
  server_tokens off;
  location / {
    limit_req zone=throttle burst=5 delay=3;
    proxy_http_version 1.1;
    proxy_pass http://127.0.0.1:8080/;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Scheme $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Script-Name /szuru;
    error_page 500 501 502 504 505 506 507 508 509 510 511 @err;
    error_page 503 @throttle;
  }

  location @err {
    return 500 "server error. please try again later.";
    default_type text/plain;
  }
  location @throttle {
    return 503 "we've detected abuse on your ip. please wait and try again later.";
    default_type text/plain;
  }
  listen 80;
  listen [::]:80;
}
}

This works nicely. The next thing I tried was securing access to the website by adding some basic_auth elements following some tutorial. Here's what changed from the code above :

server {
  server_name localhost;
  client_max_body_size 100M;
  client_body_timeout 30s;
  server_tokens off;
  auth_basic "WHAT is the capital of Assyria";
  auth_basic_user_file ..\.htpasswd;
  location / {
    limit_req zone=throttle burst=5 delay=3;
    proxy_http_version 1.1;
    auth_basic on;
    proxy_pass http://127.0.0.1:8080/;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;

note that the .htpasswd file is in the nginx folder, one level above the conf folder / this conf file. after doing this, reloading nginx and trying to access the website from my browser via port 80, I get an error (couldn't tell which one it was and can't reproduce, see following text) and the browser (firefox) asks me for login and password. But after that I constantly get a message saying "could not fetch basic configuration from the server". At this point I would have just tried to find another way to secure my server, but even after going back to the previous conf version, reloading nginx, turning off the server, deleting it (through the docker for desktop gui, red bin button, dunno what it really does) and running "docker-compose up" once more, I still get that error message. Usually, when doing this, the server throws this kind of logs at me :

2023-10-29 18:07:31 szurubooru-25-client-1  | 172.19.0.1 -> GET / HTTP/1.1 [304] - referer: - 127.0.0.1
2023-10-29 18:07:34 szurubooru-25-client-1  | 172.19.0.1 -> GET /api/info HTTP/1.1 [404] - referer: http://127.0.0.1/ 127.0.0.1
2023-10-29 18:07:34 szurubooru-25-client-1  | 172.19.0.1 -> GET /api/info HTTP/1.1 [404] - referer: http://127.0.0.1/ 127.0.0.1
2023-10-29 18:07:36 szurubooru-25-server-1  | [2023-10-29 17:07:36] szurubooru.middleware.request_logger GET /user/username (user=username, queries=6)
2023-10-29 18:07:36 szurubooru-25-client-1  | 172.19.0.1 -> GET /api/user/username?bump-login=true HTTP/1.1 [200] - referer: http://127.0.0.1/ 127.0.0.1
2023-10-29 18:07:36 szurubooru-25-server-1  | [2023-10-29 17:07:36] szurubooru.middleware.request_logger GET /pool-categories (user=username, queries=1)
2023-10-29 18:07:36 szurubooru-25-server-1  | [2023-10-29 17:07:36] szurubooru.middleware.request_logger GET /tag-categories (user=username, queries=1)
2023-10-29 18:07:36 szurubooru-25-client-1  | 172.19.0.1 -> GET /api/pool-categories HTTP/1.1 [200] - referer: http://127.0.0.1/ 127.0.0.1
2023-10-29 18:07:36 szurubooru-25-client-1  | 172.19.0.1 -> GET /api/tag-categories HTTP/1.1 [200] - referer: http://127.0.0.1/ 127.0.0.1

I managed to fix it once, after restarting my computer I think, but I don't know if that's the only thing that changed between those two occurrences. I created the password file from this site : https://www.web2generators.com/apache-tools/htpasswd-generator (even though I doubt that could help). Could you help me make it work so that I can protect my server or at least fix what's going on here ?

Eskuero commented 6 months ago

This seems to fail because there's a missmatch on the Authorization header that it's both being used by nginx's auth_basic and by szurubooru to send the initial credentials and the token afterwards so i don't think this can be fixed.

You could strip the Authorization header in the proxy pass but then you won't be able to login at all.

noirscape commented 6 months ago

Yeah, no, you're not going to get this working on szurubooru with that authentication scheme. As Eskuero says; the Authorization header is overlapping.

If you want to protect unauthorized access, it's easier to just forgo basic_auth and reconfigure your szurubooru instance to not allow anonymous reads; the frontend itself degrades gracefully if anonymous users don't have the requisite permissions. You're looking at the following permissions for an unmodified instance:

If you switch the permission on those from anonymous to regular, unauthenticated users will not be able to do anything.

SpaghettiMonkey commented 5 months ago

Sorry for the late answer, thanks, I won't waste any more of my time trying this. I ended up only allowing most of the features to approved accounts.