Closed alex1702 closed 1 year ago
What do the logs of headscale-webui say? Does it at least say you're getting to /?
[2023-03-29 10:52:21 +0200] [1] [INFO] Starting gunicorn 20.1.0
[2023-03-29 10:52:21 +0200] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2023-03-29 10:52:21 +0200] [1] [INFO] Using worker: sync
[2023-03-29 10:52:21 +0200] [7] [INFO] Booting worker with pid: 7
[2023-03-29 10:52:24,066] INFO in server: Headscale-WebUI Version: v0.5.6 / main
[2023-03-29 10:52:24,066] INFO in server: LOG LEVEL SET TO INFO
[2023-03-29 10:52:24,067] INFO in server: DEBUG STATE: False
[2023-03-29 10:52:24,067] INFO in server: Loading basic auth libraries and configuring app...
[2023-03-29 11:06:21,387] INFO in helper: All startup checks passed.
[2023-03-29 11:06:21,401] INFO in helper: Testing API key validity.
[2023-03-29 11:06:21,528] INFO in helper: Key check passed.
[2023-03-29 11:06:21,529] INFO in headscale: Getting API key information
[2023-03-29 11:06:21,651] INFO in headscale: Looking for valid API Key...
[2023-03-29 11:06:21,652] INFO in headscale: Key found.
[2023-03-29 11:06:21,653] INFO in renderer: Rendering the Overview page
[2023-03-29 11:06:21,725] INFO in renderer: Opening /etc/headscale/config.yaml
[2023-03-29 11:06:21,747] INFO in headscale: Getting machine information
[2023-03-29 11:06:21,891] INFO in headscale: Getting routes
[2023-03-29 11:06:22,026] INFO in headscale: Getting Users
That is all. Maybe test with log level debug?
Goofy. /overview and / point to the same function, so if one renders the other should as well:
@app.route('/')
@app.route('/overview')
@oidc.require_login
def overview_page():
What HTML is rendered? (in the Inspect menu in Firefox, for example)
There is no HTML page that is sent, Firefox gives an error message itself. Sorry for the german language in the browser screenshot ^^
Translated:
Error: Redirection error
An error occurred while connecting to vpnadmin.example.com
This problem can sometimes occur when cookies are disabled or refused.
Try again
For some reason I get back a 308 Permanant Redirect with the location header location: https://vpnadmin.example.com/
The very similar configuration above for vpn.example.com does not do this.
So when startup checks are ran, the page does redirect based on a few conditions if any checks fail, but it looks like yours passes...
[2023-03-29 11:06:21,387] INFO in helper: All startup checks passed.
One possibility: Have you entered your API key on the /settings page yet?
Also, is your KEY
variable in qoutes? KEY=mykey
should be KEY="mykey"
Yes, I have entered the API key under settings.
KEY is passed directly from portainer.
I have now tested setting the apostrophes in portainer, but this had no effect.
Next changed the docker-compose to:
- KEY="${KEY}"
A docker inspect shows:
"Env": [
"COLOR=red",
"SCRIPT_NAME=/",
"KEY=\"4K<censored>Po=\"",
Is now in quotation marks, but the redirect remains.
I have additionally executed a curl call without automatic redirect:
curl https://vpnadmin.example.com/ -v -u "username:<censored>"
* Trying 1.2.3.4:443...
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_CHACHA20_POLY1305_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=vpnadmin.example.com
* start date: Mar 28 22:22:23 2023 GMT
* expire date: Jun 26 22:22:22 2023 GMT
* subjectAltName: host "vpnadmin.example.com" matched cert's "vpnadmin.example.com"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Server auth using Basic with user 'alex'
* Using Stream ID: 1 (easy handle 0x55b99b207e90)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET / HTTP/2
> Host: vpnadmin.example.com
> authorization: Basic <censored>
> user-agent: curl/7.81.0
> accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 308
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 09:44:15 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
<
* TLSv1.2 (IN), TLS header, Supplemental data (23):
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="https://vpnadmin.example.com/">https://vpnadmin.example.com/</a>. If not, click the link.
* Connection #0 to host vpnadmin.example.com left intact
Interesting.. Give me a bit to play around.
Can you try the ghcr.io/ifargle/headscale-webui:testing
build?
I don't know of any changes that would fix this issue sadly, but I can't rule out I haven't made changes that would fix this issue :)
Unfortunately no change
Does gunicorn possibly think that I come in via http and would like to redirect to https for example?
That was my initial thought. Can you try removing all the http redirects? Just expose it to the https endpoint you have set up?
It should go user -> https -> traefik -> http -> container -> http -> traefik -> https > user
is the destination port 5000 correct?
I have tested both. Only https and only http same result. very strange
Yep, destination port is 5000. Let me add more debug logs to the testing build.
Cool. I'm able to replicate this :) I'll work on it and let you know when I have a fix
ok ^^
Potential fix. Try the testing build again and omit the SCRIPT_NAME
variable entirely
it works woohoo 🎉
Perfect!
Don't pull updates. It will break. I'll be pushing this to main in the next week or so
Closing -- Fixes will be in main in about 1.5 hours (multiarch builds take a while). Please use the main branch after it's available.
Thanks!
I have a similar problem with the webui behind a nginx reverse proxy.
With SCRIPT_NAME
set, I get a redirect loop. The UI should be available under https://headscale.example.com/admin
. Nginx takes care for http -> https redirects but https://headscale.example.com/admin
redirects me back to http
, causing a loop.
Removing SCRIPT_NAME
results in a 404
@iFargle , omitting SCRIPT_NAME
results in exception:
headscale-webui | File "/app/server.py", line 48, in <module>
headscale-webui | BASE_PATH = os.environ["SCRIPT_NAME"] if os.environ["SCRIPT_NAME"] != "/" else ""
headscale-webui | ~~~~~~~~~~^^^^^^^^^^^^^^^
headscale-webui | File "<frozen os>", line 679, in __getitem__
headscale-webui | KeyError: 'SCRIPT_NAME'
Attempting to set SCRIPT_NAME=/
results in the eternal redirect-loop described in this issue.
@iFargle , omitting
SCRIPT_NAME
results in exception:headscale-webui | File "/app/server.py", line 48, in <module> headscale-webui | BASE_PATH = os.environ["SCRIPT_NAME"] if os.environ["SCRIPT_NAME"] != "/" else "" headscale-webui | ~~~~~~~~~~^^^^^^^^^^^^^^^ headscale-webui | File "<frozen os>", line 679, in __getitem__ headscale-webui | KeyError: 'SCRIPT_NAME'
Attempting to set
SCRIPT_NAME=/
results in the eternal redirect-loop described in this issue.
Same issue as you. Setting it to /admin
works tho.
When I try to go to the main page I get an infinite redirect. Until my browser gives up and gives me an "error: redirect error".
I guess I might have a thinking error somewhere or a bug in traefik, I'm not a traefik expert ^^
By the way, if I call directly the subpages like https://vpnadmin.example.com/settings or https://vpnadmin.example.com/overview then it works.
Because of my little experience with traefik, I had rather used an extra subdomain and not the path "/admin". I think it is actually nicer to reach the admin interface at vpn.example.com/admin.
My docker-compose:
Environment variables are set in portainer:
Call with curl: