Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redirect loop with traefik #63

Closed
Tracked by #35
alex1702 opened this issue Mar 29, 2023 · 23 comments
Closed
Tracked by #35

redirect loop with traefik #63

alex1702 opened this issue Mar 29, 2023 · 23 comments

Comments

@alex1702
Copy link

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:

version: '3.5'

services:
  headscale:
    image: headscale/headscale:0
    command: headscale serve
    restart: unless-stopped
    networks:
      - proxy
    volumes:
      - /opt/dockerprojekte/headscale/data/hsconfig:/etc/headscale/
      - hs-data:/var/lib/headscale
    ports:
      - 27896:8080
      - 3478:3478/udp
    environment:
      - TZ=Europe/Berlin
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}.entrypoints=http"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}.rule=Host(`${DOMAIN}`)"
      - "traefik.http.middlewares.${TRAEFIKROUTERNAME}-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}.middlewares=${TRAEFIKROUTERNAME}-https-redirect"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}-secure.entrypoints=https"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}-secure.rule=Host(`${DOMAIN}`)"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}-secure.tls=true"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}-secure.service=${TRAEFIKROUTERNAME}"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}-secure.tls.certresolver=http01"
      - "traefik.http.routers.${TRAEFIKROUTERNAME}-secure.tls.domains[0].main=${DOMAIN}"
      - "traefik.http.services.${TRAEFIKROUTERNAME}.loadbalancer.server.port=8080"
      - "traefik.docker.network=proxy"

  headscale-webui:
    image: ghcr.io/ifargle/headscale-webui:latest
    networks:
      - proxy
    environment:
      - TZ=Europe/Berlin
      - COLOR=red                              # Use the base colors (ie, no darken-3, etc) - 
      - HS_SERVER=http://headscale:8080        # Reachable endpoint for your Headscale server
      - DOMAIN_NAME=https://$DOMAINADMIN       # The base domain name for this container.
      - SCRIPT_NAME=/                          # This is your applications base path (wsgi requires the name "SCRIPT_NAME")
      - KEY                                    # Generate with "openssl rand -base64 32" - used to encrypt your key on disk.
      - AUTH_TYPE=Basic                        # AUTH_TYPE is either Basic or OIDC.  Empty for no authentication
      - LOG_LEVEL=info                         # Log level.  "DEBUG", "ERROR", "WARNING", or "INFO".  Default "INFO"
      # ENV for Basic Auth (Used only if AUTH_TYPE is "Basic").  Can be omitted if you aren't using Basic Auth
      - BASIC_AUTH_USER
      - BASIC_AUTH_PASS
      # ENV for OIDC (Used only if AUTH_TYPE is "OIDC").  Can be omitted if you aren't using OIDC
#      - OIDC_AUTH_URL=https://auth.$DOMAIN/.well-known/openid-configuration # URL for your OIDC issuer's well-known endpoint
#      - OIDC_CLIENT_ID=headscale-webui         # Your OIDC Issuer's Client ID for Headscale-WebUI
#      - OIDC_CLIENT_SECRET=YourSecretHere      # Your OIDC Issuer's Secret Key for Headscale-WebUI
    volumes:
      - hsweb-data:/data                         # Headscale-WebUI's storage.  Make sure ./volume is readable by UID 1000 (chown 1000:1000 ./volume)
      - /opt/dockerprojekte/headscale/data/hsconfig:/etc/headscale/:ro # Headscale's config storage location.  Used to read your Headscale config.
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}.entrypoints=http"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}.rule=Host(`${DOMAINADMIN}`)"
      - "traefik.http.middlewares.${TRAEFIKROUTERNAME2}-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}.middlewares=${TRAEFIKROUTERNAME2}-https-redirect"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.entrypoints=https"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.rule=Host(`${DOMAINADMIN}`)"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.tls=true"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.service=${TRAEFIKROUTERNAME2}"
      # redirect /admin to /
      # - "traefik.http.middlewares.${TRAEFIKROUTERNAME2}-stripprefix.stripprefix.forceslash=true"
      # - "traefik.http.middlewares.${TRAEFIKROUTERNAME2}-stripprefix.stripprefix.prefixes=/admin/"
      # - 'traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.middlewares=${TRAEFIKROUTERNAME2}-stripprefix@docker'
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.tls.certresolver=http01"
      - "traefik.http.routers.${TRAEFIKROUTERNAME2}-secure.tls.domains[0].main=${DOMAINADMIN}"
      - "traefik.http.services.${TRAEFIKROUTERNAME2}.loadbalancer.server.port=5000"
      - "traefik.docker.network=proxy"

volumes:
  hs-data:
  hsweb-data:


networks:
  proxy:
    external: true

Environment variables are set in portainer:

TRAEFIKROUTERNAME=headscale
DOMAIN=vpn.example.com
BASIC_AUTH_USER=username
BASIC_AUTH_PASS=123456
KEY=mykey
DOMAINADMIN=vpnadmin.example.com
TRAEFIKROUTERNAME2=headscalewebui

Call with curl:

curl https://vpnadmin.example.com -v -L -u "username:123456"
*   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 0x562671e24e90)
* 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 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 3 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 5 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 7 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 9 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: b (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: d (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: f (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 11 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 13 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 15 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:16 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
............ <truncated> ....................
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Issue another request to this URL: 'https://vpnadmin.example.com/'
* Found bundle for host vpnadmin.example.com: 0x562671e1dff0 [can multiplex]
* Re-using existing connection! (#0) with host vpnadmin.example.com
* Connected to vpnadmin.example.com (1.2.3.4) port 443 (#0)
* Server auth using Basic with user 'alex'
* Using Stream ID: 65 (easy handle 0x562671e24e90)
* 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):
< HTTP/2 308 
< content-type: text/html; charset=utf-8
< date: Wed, 29 Mar 2023 07:57:17 GMT
< location: https://vpnadmin.example.com/
< server: gunicorn
< content-length: 239
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Ignoring the response-body
* Connection #0 to host vpnadmin.example.com left intact
* Maximum (50) redirects followed
curl: (47) Maximum (50) redirects followed
@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

What do the logs of headscale-webui say? Does it at least say you're getting to /?

@alex1702
Copy link
Author

[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?

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

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)

@alex1702
Copy link
Author

There is no HTML page that is sent, Firefox gives an error message itself. Sorry for the german language in the browser screenshot ^^

2023-03-29_11-32
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

@alex1702
Copy link
Author

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.

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

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"

@alex1702
Copy link
Author

alex1702 commented Mar 29, 2023

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

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

Interesting..
Give me a bit to play around.

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

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 :)

@alex1702
Copy link
Author

Unfortunately no change

Does gunicorn possibly think that I come in via http and would like to redirect to https for example?

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

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

@alex1702
Copy link
Author

is the destination port 5000 correct?

@alex1702
Copy link
Author

I have tested both. Only https and only http same result. very strange

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

Yep, destination port is 5000.
Let me add more debug logs to the testing build.

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

Cool. I'm able to replicate this :)
I'll work on it and let you know when I have a fix

@alex1702
Copy link
Author

ok ^^

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

Potential fix. Try the testing build again and omit the SCRIPT_NAME variable entirely

@alex1702
Copy link
Author

it works woohoo 🎉

@iFargle
Copy link
Owner

iFargle commented Mar 29, 2023

Perfect!

Don't pull updates. It will break. I'll be pushing this to main in the next week or so

@iFargle iFargle mentioned this issue Mar 29, 2023
11 tasks
@iFargle
Copy link
Owner

iFargle commented Mar 30, 2023

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!

@iFargle iFargle closed this as completed Mar 30, 2023
@vbrandl
Copy link

vbrandl commented Mar 31, 2023

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

@joachimtingvold
Copy link

@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.

@gergovari
Copy link

gergovari commented May 10, 2024

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants