(SOLVED) Nginx basic auth not working

Nginx reverse proxy working fine , without nginx authentication. When I add the following code to the nginx site-enabled config, I cannot access my HA server. No errors in the browser, just a looong wait then a timeout.

Setup the password for admin:

sudo htpasswd -c /etc/nginx/.htpasswd admin

then in the sites-enabled config:

location / {
..
 auth_basic "Restricted Content";
 auth_basic_user_file /etc/nginx/.htpasswd;
..
}

restart nginx service
but again, loooong wait then timeout.
No errors in the /var/log/nginx/errors.log

Removing those two lines and restart nginx, it all works again.
Not sure how to debug this.

Any ideas good folk? Need any uploads/logs?

Most likely chrome cache is messing you up.

After you enable it, try opening an incognito browser and connecting. If that works, clear your browser cache.

For the app, Iā€™m not sure how you handle it there (if it even needs it). If it does use https, then you might have to clear the app cache and reload it.

1 Like

You absolutely beauty you. ! Works !
Used incognito and got the auth popup. Logged in and transported over the VPN to my HA sever in my LAN.

I have accrued knowledge over a year or so having known ziltch about HA, config, linux, nginx, services and so on. But Ive got there. Just one thing ā€¦ how did you know it was this cache thing and why did ctrl-f5 not work in Chrome to refresh? If you dont mind please.

EDIT:
Works on my laptop.Not on my mobile.

My phone, using Chrome, logs me in through nginx auth, opens the HA dashboard, but then returns me to the nginx auth screen. Cleared chrome browser storage cache and all Chrome browsing data, cookies, images - since all time. ??

Seen this in the homeassistant.logā€¦

2020-11-17 21:53:56 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web_protocol.py", line 275, in data_received
    messages, upgraded, tail = self._request_parser.feed_data(data)
  File "aiohttp/_http_parser.pyx", line 523, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: invalid HTTP method
2020-11-17 22:00:01 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web_protocol.py", line 275, in data_received
    messages, upgraded, tail = self._request_parser.feed_data(data)
  File "aiohttp/_http_parser.pyx", line 523, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: invalid HTTP method

EDIT 2:
My bad !!
Didnt clear ā€˜all timeā€™ browser cache on phone, it was set by default to ā€˜last 24hrsā€™ so I changed to ā€˜all timeā€™ - and now itā€™s working.

EXCELLENT.

Just looking forward to the explanation from the guru Jim on this - why does this happen ?

A few years doing web development stuffā€¦browser cache is enemy #1.

It wasnā€™t so much the cache as it was probably the cookies. Basically chrome says ā€œIā€™ve been here before, I know how to log inā€¦no need to bother the user, here you go website, hereā€™s my credentialsā€

Perfect @jocnnor - Jim. Thanks.
Yup that makes sense. Otherwise the user would I presume be continually needing to enter credentials every time every site every page. How annoying. But then as it is, there is no quick way to force a re-request of credentials.
I used to code in SGML and then the wonderful HTML came along and before you knew it apps to remove the mundane markup were invented - WYSIWG stuff - and I never looked back. One got used to entering credentials all the time. Showing my age now!
Youā€™d think there would be an F5 variant to 'force re-request

Well, all sorted and thanks Jim
Daz

1 Like

EDIT:
Argggh
Spoke to soon.
Woke up this morning, using my mobile phone I fired up chrome. Using the bookmark I created last night - after clearing browser cache and all was ok - it took my to the nginx auth but this time ā€œ401 - Unauthorizedā€. Had to clear the cache again. Every time I do this is a pain in the butt because I lose all my login history and have to reenter. Anyway, works again, and every time I try . BUT if I wait for a while without visiting my nginx server then I get the 401-Unauthorized again. Seems to be a ā€œtimeoutā€ or somthing. I cant enter any login details - just always goes straight to 401-Unauthorized when I enter https:my.server.com (or rather the real url). If I clear browser cache and retry then it works - but if I leave it for a few hrs then the ā€œtimeoutā€ seems to kick in and any attempt to visit the url results in 401-unauthorized.
What gives here @jocnnor - any idea please?

my ngninx conf for the server:-

server {
    server_name my.server.net;
    ssl_certificate /etc/letsencrypt/live/my.server.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my.server.net/privkey.pem;

    # These shouldn't need to be changed
    listen [::]:443 ssl default_server ipv6only=off; 
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    proxy_buffering off;


    location / {

        # from hass forum
        proxy_pass http://192.168.1.1:8123
        proxy_set_header Host $host;
        proxy_redirect http:// https://;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # from stack overflow
        #auth_basic "Restricted Content";
        #auth_basic_user_file /etc/nginx/.htpasswd;
    }

For chrome, if you put your username infront of the url, it should ask you for the password always

https://[email protected]/

Iā€™m not 100% sure though why it sucks so much.

HTTP authentication doesnā€™t use cookies, so thereā€™s no way to store a users credentials. But this means that the session should be valid until the tab is closedā€¦until the end of time. Chrome might be closing the connection in the background though (since it doesnā€™t want to leave every single tab open). But why wont it ask for the dang password on future attempts?!?

If you want to use HTTP authentication, I would recommend combining it with a cookie approach that you can manually load in your browsers of choice. This would allow you to have your secure devices log in without requiring a password everytime, and force new connections to enter the HTTP password.

Basically, after logging in, you set the cookie in that browserā€¦and check for this cookie first before asking for the auth_basic.

add_header Set-Cookie "letmein=someRandomValue;max-age=3153600000;path=/"; #set that special cookie, when everything is ok

If you want to log in from an unsecure pc, just make sure you do it in incognito mode or clear the cache afterwards.

1 Like

Thanks for the info @jocnnor. I am trying to get it working using my HA server but it just keeps asking for a password after a day, two days, canā€™t tell - itā€™s intermittent. Something isnā€™t right. When Iā€™m off work next week I will take a closer look at the cookie solution, appreciate your help. Will come back with an update.

@jocnnor

All sorted, works now, thanks for your help.

Here is a sites-enabled file for those who arrive here via a forum search.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

map $cookie_letmein $mysite_hascookie {
  "<secret>" "yes";
  default           "no";
}

map $mysite_hascookie $mysite_authentication{
  "yes" "off"; #cookie correct  => OK
  default  "Your credentials please"; #everythingles => NOT OK
}

#server {
#    # Update this line to be your domain
#    server_name example.com;
#
#    # These shouldn't need to be changed
#    listen [::]:80 default_server ipv6only=off;
#    return 301 https://$host$request_uri;
#}

server {
    server_name <url>;
    ssl_certificate /etc/letsencrypt/live/<utL>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<url>/privkey.pem;

    # These shouldn't need to be changed
    listen [::]:443 ssl default_server ipv6only=off; # if your nginx version is >= 1.9.5 you can also add the "http2" flag here
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
    # ssl on; # Uncomment if you are using nginx < 1.15.0
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    proxy_buffering off;

    location / {

        # from RHA Guides
        proxy_pass http://192.168.2.10:8123;
        proxy_set_header Host $host;
        proxy_redirect http:// https://;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        add_header Set-Cookie "letmein=<secret>;max-age=3153600000;path=/"; #set that special cookie, when everything is ok
        auth_basic  $mysite_authentication;
        #auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

3 Likes

I might add this to my config too lol. Thanks for being my test subject!

I recently noticed a random login attempt to my home assistant from some ip address. One more layer of security should help out!

OMGā€¦ I was about to tear my hair out. This saved me!