Disallow http access to Flowfuse, Nodered, and http-in nodes

I’ve got Flowfuse running in a k8s cluster within eks. I’m using an Amazon certificate for ssl termination and https works great.

My problem is that I can access the Flowfuse app and log in at http://forge.mydomain.com. I can also access http-in nodes through http://myinstance.mydomain.com/http-in-test

I’d like to disallow http access completely and force https access for Flowfuse, Node-red Instances, and any http-in endpoints that get setup. Ideally with some sort of redirect to https, but if that’s not a possibility just disabling http works too.

I’ve tried adding

ingress:
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

to my Flowfuse customization.yml file used when installing Flowfuse, but then when I try to access Flowfuse, I get ERR_TOO_MANY_REDIRECTS from the browser.

I’ve looked at handling the https redirect with the load balancer, but the Flowfuse k8s cluster configuration uses an NLB rather than an ALB, so that’s not an option either.

I’m pretty new to Flowfuse, so there’s probably an obvious solution somewhere I haven’t found yet, but I’m a little stuck.

Thanks for the help in advance

nginx.ingress.kubernetes.io/force-ssl-redirect: "true" should be the right approach.

If you use curl to test in verbose mode it would be interesting to see what the redirects that are sent which are triggering the error.

Here’s the output from that:

$ curl -v https://forge.my.domain.com
*   Trying 34.228.179.122:443...
* Connected to forge.my.domain.com (34.228.179.122) port 443
* ALPN: curl offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=*.my.otherdomain.com
*  start date: Mar 20 00:00:00 2024 GMT
*  expire date: Apr 19 23:59:59 2025 GMT
*  subjectAltName: host "forge.my.domain.com" matched cert's "*.my.domain.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/1.x
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Fri, 22 Mar 2024 23:50:03 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
<html>
<head><title>308 Permanent Redirect</title></head>
<body>
<center><h1>308 Permanent Redirect</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host forge.my.domain.com left intact

Note I’m redacting my actual domain from the post, but from the output of the curl command, you can see a reference to *.my.otherdomain.com. I have that certificate set up with two domains . *.my.domain.com and *.my.otherdomain.com

Maybe there’s some weirdness caused by the two domains?

Hi,

Sorry can you try again with curl and also include the -L flag so it will follow the redirects.

Also can you include a redaced version of the customization.yaml you passed to the helm chart (did you include forge.https = true)

Ahh, I didn’t have forge.https = true, I had just removed that line completely. After adding that, the force-ssl-redirect ingress annotation seems to be working as I would expect for the Flowfuse UI as well as the Nodered editor.

I can still access the Flowfuse api over plain http though as well as any http-in nodes I set up for a Nodered instance. I see a requireHttps setting for Nodered, but don’t see that as one of the options available in the Instance settings or Template settings through Flowfuse.

Do I need to restart/delete any of the pods? Or is there some other step to force https for the api and http-in nodes?

$ curl -Lv http://forge.my.domain.com/api/v1/admin/stats -H "Authorization: Bearer <my_access_token>"
*   Trying 18.209.253.51:80...
* Connected to forge.my.domain.com (18.209.253.51) port 80
> GET /api/v1/admin/stats HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
> Authorization: Bearer <my_access_token>
>
< HTTP/1.1 200 OK
< Date: Sun, 24 Mar 2024 02:51:20 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 306
< Connection: keep-alive
< Origin-Agent-Cluster: ?1
< Referrer-Policy: origin-when-cross-origin
< Strict-Transport-Security: max-age=3600; preload
< X-Content-Type-Options: nosniff
< X-DNS-Prefetch-Control: off
< X-Download-Options: noopen
< X-Frame-Options: DENY
< X-Permitted-Cross-Domain-Policies: none
< X-XSS-Protection: 0
<
* Connection #0 to host forge.my.domain.com left intact
{"userCount":2,"maxUsers":150,"adminCount":0,"inviteCount":0,"teamCount":1,"maxTeams":50,"teamsByType":{"starter":1},"instanceCount":2,"maxInstances":50,"instancesByState":{"running":2},"deviceCount":0,"maxDevices":50,"devicesByMode":{},"devicesByLastSeen":{"never":0,"day":0,"week":0,"month":0,"older":0}}
$ curl -Lv http://myinstance.my.domain.com/http-in-test
*   Trying 18.209.253.51:80...
* Connected to myinstance.my.domain.com (18.209.253.51) port 80
> GET /http-in-test HTTP/1.1
> Host: myinstance.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 24 Mar 2024 03:07:15 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 13
< Connection: keep-alive
< Access-Control-Allow-Origin: *
< X-Powered-By: Express
< X-Content-Type-Options: nosniff
< ETag: W/"d-pedE0BZFQNM7HX6mFsKPL6l+dUo"
<
* Connection #0 to host myinstance.my.domain.com left intact
{"foo":"bar"}

Apologies, the reply before this I didn’t realize that I had removed the

ingress:
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

section from my customization.yaml file. I’m leaving the reply above in case you’ve already seen it.

After adding that annotation back I’m still getting ERR_TOO_MANY_REDIRECTS, even with https: true

Here’s my customization.yaml file:

forge:
  entryPoint: forge.my.domain.com
  domain: my.domain.com
  https: true
  localPostgresql: true
  cloudProvider: aws
  aws:
    IAMRole: <IAM role arn>
  email:
    enabled: false
  managementSelector:
    role: management
  projectSelector:
    role: projects

ingress:
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

Here’s the output from curl -Lv

$ curl -Lv https://forge.my.domain.com
*   Trying 34.228.179.122:443...
* Connected to forge.my.domain.com (34.228.179.122) port 443
* ALPN: curl offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=*.my.otherdomain.com
*  start date: Mar 20 00:00:00 2024 GMT
*  expire date: Apr 19 23:59:59 2025 GMT
*  subjectAltName: host "forge.my.domain.com" matched cert's "*.my.domain.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/1.x
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:30 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:31 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:32 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Issue another request to this URL: 'https://forge.my.domain.com/'
* Found bundle for host: 0x22403c0 [serially]
* Can not multiplex, even if we wanted to
* Re-using existing connection with host forge.my.domain.com
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 04:09:33 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Maximum (50) redirects followed
curl: (47) Maximum (50) redirects followed

OK, there is something strange going on here and it looks like it’s in the nginx ingress controller. I suggest you remove the annotation for now.

(you should suspend and restart all project after changing the annotation so the ingress objects get recreated).

The forge.https = true will ensure that the FlowForge app requires HTTPS (it sets the HTST header)

As for the projects will need to dig some more, there are several issues on the ingress-nginx github talking about similar problems e.g.

I haven’t got to to bottom of them all yet.

Assuming you have installed the ingress-nginx controller using instructions from the FlowFuse documentation, could you please change the value of controller.service.targetPorts.https from http to https and reconfigure the nginx-ingress installation using Helm?

Once reconfigured, please enable the nginx.ingress.kubernetes.io/force-ssl-redirect annotation and verify if the application, as well as NodeRED instances, are available over a secured connection only.

Piotr, I tried this out in the order you recommended and got errors trying to send plain http to an https port.

$ curl -Lv https://forge.my.domain
*   Trying 34.228.179.122:443...
* Connected to forge.my.domain (34.228.179.122) port 443
* ALPN: curl offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=*.my.otherdomain.com
*  start date: Mar 20 00:00:00 2024 GMT
*  expire date: Apr 19 23:59:59 2025 GMT
*  subjectAltName: host "forge.my.domain" matched cert's "*.my.domain"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/1.x
> GET / HTTP/1.1
> Host: forge.my.domain
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Date: Mon, 25 Mar 2024 15:33:48 GMT
< Content-Type: text/html
< Content-Length: 248
< Connection: close
<
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx</center>
</body>
</html>
* Closing connection
* TLSv1.2 (OUT), TLS alert, close notify (256):

I’ve removed the annotation for now and continued poking around with https: true in my customization.yaml, but can still access flowfuse over http. Earlier, I had an open https session which made me think an http → https redirect was happening.

Note the Strict-Transport-Security header in the request.

$ curl -Lv http://forge.my.domain.com
*   Trying 34.228.179.122:80...
* Connected to forge.my.domain.com (34.228.179.122) port 80
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Mon, 25 Mar 2024 18:04:58 GMT
< Content-Type: text/html; charset=UTF-8
< Content-Length: 870
< Connection: keep-alive
< Origin-Agent-Cluster: ?1
< Referrer-Policy: origin-when-cross-origin
< Strict-Transport-Security: max-age=3600; preload
< X-Content-Type-Options: nosniff
< X-DNS-Prefetch-Control: off
< X-Download-Options: noopen
< X-Frame-Options: DENY
< X-Permitted-Cross-Domain-Policies: none
< X-XSS-Protection: 0
< accept-ranges: bytes
< cache-control: public, max-age=0
< last-modified: Wed, 28 Feb 2024 13:19:04 GMT
< etag: W/"366-18defde5d40"
<
* Connection #0 to host forge.my.domain.com left intact
<!doctype html><html lang=""><head><link rel="icon" href="/favicon.ico"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>FlowFuse</title><script>/*inject-ff-scripts*/</script><link rel="icon" href="/app/favicon.ico"><script defer="defer" src="/app/runtime.js"></script><script defer="defer" src="/app/vendors.js"></script><script defer="defer" src="/app/main.js"></script><link href="/app/main.css" rel="stylesheet"></head><body class="bg-white"><noscript><strong>We're sorry but FlowFuse doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

I can also access and login to Flowfuse in the browser over http

Although counter intuitive, from my understanding of this rfc, Strict-Transport-Security headers are only respected over https

If an HTTP response is received over insecure transport, the UA MUST ignore any present STS header field(s).

https://www.rfc-editor.org/rfc/rfc6797#section-8.1

current customization.yaml

forge:
  entryPoint: forge.my.domain.com
  domain: my.domain.com
  https: true
  localPostgresql: true
  cloudProvider: aws
  aws:
    IAMRole: <IAM role arn>
  email:
    enabled: false
  managementSelector:
    role: management
  projectSelector:
    role: projects

Okay, I’ve got http traffic redirecting to https, but I’m curious for your thoughts on this approach.

I think the issue is that the load balancer is terminating ssl and sending all downstream traffic as http, but it’s the ingress controller that’s forcing ssl redirect. Because the ingress controller is downstream of the load balancer, it receives http from the load balancer and then redirects to https which goes back to the load balancer and you get this loop.

To solve it, I edited the nginx-values.yaml file to this:

controller:
  # publishService required to Allow ELB Alias for DNS registration w/ external-dns
  publishService:
    enabled: true
  tcp:
    configNameSpace: $(POD_NAMESPACE)/tcp-services
  udp:
    configNameSpace: $(POD_NAMESPACE)/udp-services
  config:
    proxy-body-size: "0"
  service:
    # AWS Annotations for LoadBalaner with Certificate ARN
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-ssl-cert: <ssl cert arn>
      service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "ssl"
      service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
      service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
      service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "120"

Note the change from "tcp" to "ssl" for service.beta.kubernetes.io/aws-load-balancer-backend-protocol and the removal of the targetPorts.https: http section

And here’s my customization.yaml file:

forge:
  entryPoint: forge.my.domain.com
  domain: my.domain.com
  https: true
  localPostgresql: true
  cloudProvider: aws
  aws:
    IAMRole: <arn>
  email:
    enabled: false
  managementSelector:
    role: management
  projectSelector:
    role: projects

ingress:
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

So with this, tls termination doesn’t happen at the loadbalancer, it happens past that at ingress nginx.

After upgrading both flowforge and ingress-nginx with helm, any http requests to Flowfuse, Nodered instances, or any http-in nodes get redirected to https.

$ curl -Lv http://forge.my.domain.com
*   Trying 18.209.253.51:80...
* Connected to forge.my.domain.com (18.209.253.51) port 80
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 20:21:25 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://forge.my.domain.com
<
* Ignoring the response-body
* Connection #0 to host forge.my.domain.com left intact
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://forge.my.domain.com/'
*   Trying 18.209.253.51:443...
* Connected to forge.my.domain.com (18.209.253.51) port 443
* ALPN: curl offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=*.my.otherdomain.com
*  start date: Mar 20 00:00:00 2024 GMT
*  expire date: Apr 19 23:59:59 2025 GMT
*  subjectAltName: host "forge.my.domain.com" matched cert's "*.my.domain.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/1.x
> GET / HTTP/1.1
> Host: forge.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Mon, 25 Mar 2024 20:21:25 GMT
< Content-Type: text/html; charset=UTF-8
< Content-Length: 870
< Connection: keep-alive
< Origin-Agent-Cluster: ?1
< Referrer-Policy: origin-when-cross-origin
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< X-Content-Type-Options: nosniff
< X-DNS-Prefetch-Control: off
< X-Download-Options: noopen
< X-Frame-Options: DENY
< X-Permitted-Cross-Domain-Policies: none
< X-XSS-Protection: 0
< accept-ranges: bytes
< cache-control: public, max-age=0
< last-modified: Wed, 28 Feb 2024 13:19:04 GMT
< etag: W/"366-18defde5d40"
<
* Connection #1 to host forge.my.domain.com left intact
<!doctype html><html lang=""><head><link rel="icon" href="/favicon.ico"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>FlowFuse</title><script>/*inject-ff-scripts*/</script><link rel="icon" href="/app/favicon.ico"><script defer="defer" src="/app/runtime.js"></script><script defer="defer" src="/app/vendors.js"></script><script defer="defer" src="/app/main.js"></script><link href="/app/main.css" rel="stylesheet"></head><body class="bg-white"><noscript><strong>We're sorry but FlowFuse doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
$ curl -Lv http://myinstance.my.domain.com/test-http-in
*   Trying 34.228.179.122:80...
* Connected to myinstance.my.domain.com (34.228.179.122) port 80
> GET /test-http-in HTTP/1.1
> Host: myinstance.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Mon, 25 Mar 2024 20:21:57 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://myinstance.my.domain.com/test-http-in
<
* Ignoring the response-body
* Connection #0 to host myinstance.my.domain.com left intact
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://myinstance.my.domain.com/test-http-in'
*   Trying 34.228.179.122:443...
* Connected to myinstance.my.domain.com (34.228.179.122) port 443
* ALPN: curl offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=*.my.otherdomain.com
*  start date: Mar 20 00:00:00 2024 GMT
*  expire date: Apr 19 23:59:59 2025 GMT
*  subjectAltName: host "myinstance.my.domain.com" matched cert's "*.my.domain.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/1.x
> GET /test-http-in HTTP/1.1
> Host: myinstance.my.domain.com
> User-Agent: curl/8.3.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Mon, 25 Mar 2024 20:21:57 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 13
< Connection: keep-alive
< Access-Control-Allow-Origin: *
< X-Powered-By: Express
< X-Content-Type-Options: nosniff
< ETag: W/"d-pedE0BZFQNM7HX6mFsKPL6l+dUo"
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #1 to host myinstance.my.domain.com left intact
{"foo":"bar"}

Since you changed the way NLB is communicating with the ingress controller to ssl, nginx can properly handle the redirect from http to https once it receives unencrypted traffic. That is why force-ssl-redirect annotation is not causing a redirect loop anymore.
I think this is the best way to handle http to https redirect with a NLB in front of the ingress controller and TLS certificated terminated on the load balancer level.