Bubka / 2FAuth

A Web app to manage your Two-Factor Authentication (2FA) accounts and generate their security codes
https://docs.2fauth.app/
GNU Affero General Public License v3.0
1.98k stars 135 forks source link

Self Hosted Docker Compose Install - Blank Home Page #340

Open yodaphone opened 3 months ago

yodaphone commented 3 months ago

Version

5.2.0

Details & Steps to reproduce

I created the server with docker compose with version 5.2.0 tag and default file as described and in both instances i only get a blank page when i browse to the URL

Expectation

Supposed to see a login page

attaching screen shot of web console from browser. it has some connection_refused issues.

slGBynHeyy

Error & Logs

[2024-05-29 10:26:16] local.DEBUG: ReleaseRadarActivated event dispatched
[2024-05-29 10:26:16] local.INFO: Release scan started
[2024-05-29 10:26:16] local.NOTICE: App setting 'lastRadarScan' set to 1716996376
[2024-05-29 10:26:16] local.NOTICE: App setting 'latestRelease' reset to default

Docker compose console logs

docker compose up
WARN[0000] The "PUSHER_APP_KEY" variable is not set. Defaulting to a blank string.
WARN[0000] The "PUSHER_APP_CLUSTER" variable is not set. Defaulting to a blank string.
[+] Running 19/18
 ✔ 2fauth Pulled                                                                                                                                                                                                                        3.8s
   ✔ 4abcf2066143 Already exists                                                                                                                                                                                                        0.0s
   ✔ 60090a118777 Already exists                                                                                                                                                                                                        0.0s
   ✔ 8e1c3902bf6c Already exists                                                                                                                                                                                                        0.0s
   ✔ cb3e2b31d636 Already exists                                                                                                                                                                                                        0.0s
   ✔ 2300f1f7b35d Already exists                                                                                                                                                                                                        0.0s
   ✔ e698995d0bf8 Already exists                                                                                                                                                                                                        0.0s
   ✔ d803cb217c1a Already exists                                                                                                                                                                                                        0.0s
   ✔ b3865a63586c Already exists                                                                                                                                                                                                        0.0s
   ✔ 9fa3067f6190 Already exists                                                                                                                                                                                                        0.0s
   ✔ 9e8d7f80c995 Already exists                                                                                                                                                                                                        0.0s
   ✔ 7a7edf842cdc Already exists                                                                                                                                                                                                        0.0s
   ✔ 1f6771abd4d2 Already exists                                                                                                                                                                                                        0.0s
   ✔ 4f4fb700ef54 Already exists                                                                                                                                                                                                        0.0s
   ✔ 7f95e190cc39 Already exists                                                                                                                                                                                                        0.0s
   ✔ dda85c75a9db Already exists                                                                                                                                                                                                        0.0s
   ✔ f1a198813db7 Already exists                                                                                                                                                                                                        0.0s
   ✔ 94a381b9627f Already exists                                                                                                                                                                                                        0.0s
   ✔ 75fdc8739d6e Already exists                                                                                                                                                                                                        0.0s
[+] Running 1/1
 ✔ Container 2fauth  Created                                                                                                                                                                                                            0.1s
Attaching to 2fauth
2fauth  | Running version 5.2.0 commit a707ad3 built on 2024-05-29T14:27:28Z
2fauth  | supervisord version: v0.6.8
2fauth  | PHP 8.2.19 (fpm-fcgi) (built: May  9 2024 19:31:11)
2fauth  | nginx version: nginx/1.24.0
2fauth  | DB_DATABASE sets with default path, we will use a symlink
2fauth  | Actual db file will be /2fauth/database.sqlite
2fauth  | /srv/database/database.sqlite is now a symlink to /2fauth/database.sqlite
2fauth  |
2fauth  |    INFO  Clearing cached bootstrap files.
2fauth  |
2fauth  |   events ............................................................ 2ms DONE
2fauth  |   views ............................................................. 9ms DONE
2fauth  |   cache ............................................................. 2ms DONE
2fauth  |   route ............................................................. 1ms DONE
2fauth  |   config ............................................................ 1ms DONE
2fauth  |   compiled .......................................................... 1ms DONE
2fauth  |
2fauth  |
2fauth  |    INFO  Configuration cached successfully.
2fauth  |
2fauth  |
2fauth  |    INFO  Routes cached successfully.
2fauth  |
2fauth  |
2fauth  |    INFO  Blade templates cached successfully.
2fauth  |
2fauth  | time="2024-05-29T15:09:52Z" level=info msg="load configuration from file" file=/etc/supervisor/supervisord.conf
2fauth  | 192.168.11.50 - - [29/May/2024:15:10:02 +0000] "GET /login HTTP/1.1" 200 2779 "-" "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36"
2fauth  | 192.168.11.50 - - [29/May/2024:15:10:25 +0000] "GET / HTTP/1.1" 200 2779 "-" "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36"

Execution environment

No response

Containerization

Additional information

No response

yodaphone commented 3 months ago

my compose file

services:
  2fauth:
    image: 2fauth/2fauth
    container_name: 2fauth
    volumes:
      - ./2fauth:/2fauth
    ports:
      - 8000:8000/tcp
    environment:
      # You can change the name of the app
      - APP_NAME=2FAuth
      # You can leave this on "local". If you change it to production most console commands will ask for extra confirmation.
      # Never set it to "testing".
      - APP_ENV=local
      # The timezone for your application, which is used to record dates and times to database. This global setting can be
      # overridden by users via in-app settings for a personalised dates and times display.
      # If this setting is changed while the application is already running, existing records in the database won't be updated
      - APP_TIMEZONE=ETC
      # Set to true if you want to see debug information in error screens.
      - APP_DEBUG=true
      # This should be your email address
      - SITE_OWNER=someuser@gmail.com
      # The encryption key for  our database and sessions. Keep this very secure.
      # If you generate a new one all existing data must be considered LOST.
      # Change it to a string of exactly 32 chars or use command `php artisan key:generate` to generate it
      - APP_KEY=SarrowWagesNomovingCursesUnretir
      # This variable must match your installation's external address.
      # Webauthn won't work otherwise.
      - APP_URL=http://192.168.11.75
      # If you want to serve js assets from a CDN (like https://cdn.example.com),
      # uncomment the following line and set this var with the CDN url.
      # Otherwise, let this line commented.
      # - ASSET_URL=http://localhost
      #
      # Turn this to true if you want your app to react like a demo.
      # The Demo mode reset the app content every hours and set a generic demo user.
      - IS_DEMO_APP=false
      # The log channel defines where your log entries go to.
      # 'daily' is the default logging mode giving you 7 daily rotated log files in /storage/logs/.
      # Also available are 'errorlog', 'syslog', 'stderr', 'papertrail', 'slack' and a 'stack' channel
      # to combine multiple channels into a single one.
      - LOG_CHANNEL=daily
      # Log level. You can set this from least severe to most severe:
      # debug, info, notice, warning, error, critical, alert, emergency
      # If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
      # nothing will get logged, ever.
      - LOG_LEVEL=debug
      # Database config (can only be sqlite)
      - DB_DATABASE="/srv/database/database.sqlite"
      # If you're looking for performance improvements, you could install memcached.
      - CACHE_DRIVER=file
      - SESSION_DRIVER=file
      # Mail settings
      # Refer your email provider documentation to configure your mail settings
      # Set a value for every available setting to avoid issue
      - MAIL_MAILER=log
      - MAIL_HOST=smtp.sendgrid.net
      - MAIL_PORT=465
      - MAIL_USERNAME=apikey
      - MAIL_PASSWORD=XXXXXXXXXXXXXXXXXXX
      - MAIL_ENCRYPTION=tls
      - MAIL_FROM_NAME=someuser
      - MAIL_FROM_ADDRESS=someuser@gmail.com
      # SSL peer verification.
      # Set this to false to disable the SSL certificate validation.
      # WARNING
      # Disabling peer verification can result in a major security flaw.
      # Change it only if you know what you're doing.
      - MAIL_VERIFY_SSL_PEER=true
      # API settings
      # The maximum number of API calls in a minute from the same IP.
      # Once reached, all requests from this IP will be rejected until the minute has elapsed.
      # Set to null to disable the API throttling.
      - THROTTLE_API=60
      # Authentication settings
      # The number of times per minute a user can fail to log in before being locked out.
      # Once reached, all login attempts will be rejected until the minute has elapsed.
      # This setting applies to both email/password and webauthn login attemps.
      - LOGIN_THROTTLE=5
      # The default authentication guard
      # Supported:
      #   'web-guard' : The Laravel built-in auth system (default if nulled)
      #   'reverse-proxy-guard' : When 2FAuth is deployed behind a reverse-proxy that handle authentication
      # WARNING
      # When using 'reverse-proxy-guard' 2FAuth only look for the dedicated headers and skip all other built-in
      # authentication checks. That means your proxy is fully responsible of the authentication process, 2FAuth will
      # trust him as long as headers are presents.
      - AUTHENTICATION_GUARD=web-guard
      # Authentication log retention time, in days.
      # Log entries older than that are automatically deleted.
      - AUTHENTICATION_LOG_RETENTION=365
      # Name of the HTTP headers sent by the reverse proxy that identifies the authenticated user at proxy level.
      # Check your proxy documentation to find out how these headers are named (i.e 'REMOTE_USER', 'REMOTE_EMAIL', etc...)
      # (only relevant when AUTHENTICATION_GUARD is set to 'reverse-proxy-guard')
      - AUTH_PROXY_HEADER_FOR_USER=null
      - AUTH_PROXY_HEADER_FOR_EMAIL=null
      # Custom logout URL to open when using an auth proxy.
      - PROXY_LOGOUT_URL=null
      # WebAuthn settings
      # Relying Party name, aka the name of the application. If blank, defaults to APP_NAME. Do not set to null.
      - WEBAUTHN_NAME=Mobizent
      # Relying Party ID, should equal the site domain (i.e 2fauth.example.com).
      # If null, the device will fill it internally (recommended)
      # See https://webauthn-doc.spomky-labs.com/prerequisites/the-relying-party#how-to-determine-the-relying-party-id
      - WEBAUTHN_ID=null
      # Use this setting to control how user verification behave during the
      # WebAuthn authentication flow.
      #
      # Most authenticators and smartphones will ask the user to actively verify
      # themselves for log in. For example, through a touch plus pin code,
      # password entry, or biometric recognition (e.g., presenting a fingerprint).
      # The intent is to distinguish one user from any other.
      #
      # Supported:
      #   'required': Will ALWAYS ask for user verification
      #   'preferred' (default) : Will ask for user verification IF POSSIBLE
      #   'discouraged' : Will NOT ask for user verification (for example, to minimize disruption to the user interaction flow)
      - WEBAUTHN_USER_VERIFICATION=preferred
      #### SSO settings (for Socialite) ####
      # Uncomment and complete lines for the OAuth providers you want to enable.
      # - OPENID_AUTHORIZE_URL=
      # - OPENID_TOKEN_URL=
      # - OPENID_USERINFO_URL=
      # - OPENID_CLIENT_ID=
      # - OPENID_CLIENT_SECRET=
      # - GITHUB_CLIENT_ID=
      # - GITHUB_CLIENT_SECRET=
      # Use this setting to declare trusted proxied.
      # Supported:
      #   '*': to trust any proxy
      #   A comma separated IP list: The list of proxies IP to trust
      - TRUSTED_PROXIES=*
      # Proxy for outgoing requests like new releases detection or logo fetching.
      # You can provide a proxy URL that contains a scheme, username, and password.
      # For example, "http://username:password@192.168.16.1:10".
      - PROXY_FOR_OUTGOING_REQUESTS=null
      # Leave the following configuration vars as is.
      # Unless you like to tinker and know what you're doing.
      - BROADCAST_DRIVER=log
      - QUEUE_DRIVER=sync
      - SESSION_LIFETIME=120
      - REDIS_HOST=127.0.0.1
      - REDIS_PASSWORD=null
      - REDIS_PORT=6379
      - PUSHER_APP_ID=
      - PUSHER_APP_KEY=
      - PUSHER_APP_SECRET=
      - PUSHER_APP_CLUSTER=mt1
      - VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
      - VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
      - MIX_ENV=local
Bubka commented 3 months ago

Hi,

Are you using a Mac? I have found many threads where ERR_CONNECTION_REFUSED is related to MacOS.

Anyway, what is 192.168.11.75? a proxy?

Requests to the app url succeed but those to assets (css/js/img files) failed. It could be a permissions problem with the /2fauth folder on the host side, although the ERR_CONNECTION_REFUSED is not really relevant in this case.

yodaphone commented 3 months ago

I'm running this in a Ubuntu VM with docker compose

192.168.11.75 is the IP address of the VM

i have a reverse proxy with caddy, but before i deploy wanted to check it internally

caglaryalcin commented 3 months ago

I have the same problem. I connect to the nas device with a proxy. image

sgtrusty commented 3 months ago

It works fine, use port 80. Php files need to be refactored to include port from environment passed by docker. Alternatively you can setup an internal network using docker and pipe it through there in compose.

yodaphone commented 3 months ago

Alternatively you can setup an internal network using docker and pipe it through there in compose.

Can you please give me an example of how to do this?

sgtrusty commented 2 months ago

Alternatively you can setup an internal network using docker and pipe it through there in compose.

Can you please give me an example of how to do this?

version: "3.9"
services:
  2fauth:
    build:
      context: .
      dockerfile: 2fauth.dockerfile
      args:
        - ANY_BUILD_ARGS_HERE=${ANY_BUILD_ARGS_HERE:-default_value}
    environment:
      - ANY_RUNTIME_ENV_HERE=${ANY_RUNTIME_ENV_HERE:-default_value}
    ports:
      - "80:8000"
    networks:
      mynet:
        ipv4_address: 172.66.0.10
networks:
  mynet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.66.0.0/24

Something like this. You need to fine tune it to your requirements. Make sure that the external (network) port 80 is mapped to the internal (container) port 8000, in this case.

It would be nice if the original issues could be addressed and php instead would use the environment port as well in the libs responsible for manufacturing internal URLs.

caglaryalcin commented 2 months ago

What's the difference between port 80 and 8000? About a year ago, I wasn't experiencing issues with the same configuration. I can't even go directly from local without a proxy, by the way.

sgtrusty commented 2 months ago

What's the difference between port 80 and 8000? About a year ago, I wasn't experiencing issues with the same configuration. I can't even go directly from local without a proxy, by the way.

I am not an official maintainer for this project so I don't know what you are referring to. If I have spare time I might address the issues by making the appropriate changes to the php url templating. What do you mean about going from local w/o a proxy? If you use 80:8000 mapping in normal docker command it works with the internal network. Keep in mind, you'd have to access from https://localhost:80/ though (or omit the port entirely).

For security and configuration matters I prefer mapping it to a virtual network subnet though.

caglaryalcin commented 2 months ago

What's the difference between port 80 and 8000? About a year ago, I wasn't experiencing issues with the same configuration. I can't even go directly from local without a proxy, by the way.

I am not an official maintainer for this project so I don't know what you are referring to. If I have spare time I might address the issues by making the appropriate changes to the php url templating. What do you mean about going from local w/o a proxy? If you use 80:8000 mapping in normal docker command it works with the internal network. Keep in mind, you'd have to access from https://localhost:80/ though (or omit the port entirely).

For security and configuration matters I prefer mapping it to a virtual network subnet though.

What I'm trying to say is that when I go to nas with cloudflared, I still go with localhost:port 8000 but with cloudflare proxy in between.

Bubka commented 2 months ago

Starting with v5.2, the NGINX docker image also listens to ipv6. Is it possible that this change impacts your configurations?

caglaryalcin commented 2 months ago

Starting with v5.2, the NGINX docker image also listens to ipv6. Is it possible that this change impacts your configurations?

Yes, when I use docker desktop on my local computer and set it to 80:8000 I can go to the homepage, what is the reason for this? Can't we use a port other than 80?

I don't know what the difference between this image and yours is, but I was able to use 80 external ports with this image. https://hub.docker.com/r/easysoft/2fauth

Bubka commented 2 months ago

Does the v5.1 image run without issue?

caglaryalcin commented 2 months ago

Does the v5.1 image run without issue?

I tried with v5.1 and 5.0.3 image. I have the same problem.

Edit: I have tried almost all images from old to new. It works fine up to v5.0.2. In v5.0.3 and later image versions I get the error “ERR_CONNECTION_REFUSED”. Whatever is happening happens between v5.0.2-v5.0.3 :)

Bubka commented 2 months ago

Thanks for all these tests.

Whatever is happening happens between v5.0.2-v5.0.3 :)

Few things have changed between the two: https://github.com/Bubka/2FAuth/compare/v5.0.2...v5.0.3 The only change that could affect docker or the configuration is this one: https://github.com/Bubka/2FAuth/commit/98f711800d71501a305b94c1294b8c238c7af3c7

Do you have ASSET_URL defined in your compose file?

caglaryalcin commented 2 months ago

No, it is not defined. I am sharing the exact compose file I use.

version: "3" services: 2fauth: image: 2fauth/2fauth:5.0.3 container_name: 2fauth volumes:

Bubka commented 2 months ago

For the record: The ASSET_URL env var has been introduced in v5.0.2 to fix an issue with new asset url generation in v5.0. In v5.0.2 and v5.0.3, having ASSET_URL set is mandatory. Starting with 5.0.4, ASSET_URL is optional. If omitted, the value of APP_URL is used as default asset url.

So, for your v5.0.3 compose file to work, I had to make 2 changes :

When targeting v5.0.4 or a higher image version, the configuration works as is, or without ASSET_URL.

The weird part is the error type. On my test machine the error was ERR_BLOCKED_BY_ORB, not ERR_CONNECTION_REFUSED 🤨

caglaryalcin commented 2 months ago

Yes I was able to run v5.0.3 and the latest version, but for me it worked when I typed the NAS IP directly instead of localhost. When I typed localhost I got ERR_CONNECTION_REFUSED error again. Thank you for your great support and implementation :)

image

Bubka commented 2 months ago

hum, for me it's a proxy issue then (you previously said that there is a proxy in front of the nas)

caglaryalcin commented 2 months ago

Yeah, probably because it's a proxy..

Lebowski89 commented 2 months ago

Struggling with blank screen. Not sure if it is how I have set up the Traefik labels (works for 50 other containers):

- name: create 2fauth container
  community.docker.docker_container:
    name: '2fauth'
    image: '2fauth/2fauth'
    pull: true
    state: started
    networks:
      - name: 'redis_2fauth'
      - name: 'postgres'
      - name: 'traefik_proxy'
    env:
      PUID: '{{ PUID }}'
      PGID: '{{ PGID }}'
      TZ: '{{ TIMEZONE }}'
      APP_NAME: '2fauth'
      APP_ENV: 'local'
      APP_TIMEZONE: '{{ TIMEZONE }}'
      SITE_OWNER: '{{ GMAIL }}'
      APP_KEY: '<app key>'
      APP_URL: 'https://2fauth.{{ DOMAINNAME_1 }}'
      ASSET_URL: 'https://2fauth.{{ DOMAINNAME_1 }}'
      AUTHENTICATION_GUARD: 'reverse-proxy-guard'
      AUTH_PROXY_HEADER_FOR_USER: '2FAUTH-User'
      TRUSTED_PROXIES: '*'
      LOG_CHANNEL: 'daily'
      LOG_LEVEL: 'info'
      DB_CONNECTION: 'pgsql'
      DB_DATABASE: '2fauth'
      DB_HOST: 'postgres14'
      DB_PORT: '5432'
      DB_USERNAME: '<user>'
      DB_PASSWORD: '<pass>'
      #CACHE_DRIVER: 'redis'
      #SESSION_DRIVER: 'redis'
      #SESSION_STORE: 'redis'
      #REDIS_HOST: 'redis-2fauth'
      #REDIS_PASSWORD: '<Password>'
      #REDIS_PORT: '6379'
    labels:
      # traefik
      traefik.enable: 'true'
      traefik.docker.network: 'traefik_proxy'
      ## routers
      traefik.http.routers.2fauth.entrypoints: 'http'
      traefik.http.routers.2fauth.rule: 'Host(`2fauth.{{ DOMAINNAME_1 }}`)'
      ## middlewares
      traefik.http.middlewares.2fauth-custom-header.headers.customrequestheaders.REMOTE_USER: '2FAUTH-User'
      traefik.http.middlewares.2fauth-https-redirect.redirectscheme.scheme: 'https'
      traefik.http.routers.2fauth.middlewares: 'auth@file,2fauth-https-redirect,2fauth-custom-header'
      ## routers - secure
      traefik.http.routers.2fauth-secure.entrypoints: 'https'
      traefik.http.routers.2fauth-secure.rule: 'Host(`2fauth.{{ DOMAINNAME_1 }}`)'
      traefik.http.routers.2fauth-secure.tls: 'true'
      ## services
      traefik.http.routers.2fauth-secure.service: '2fauth'
      traefik.http.services.2fauth.loadbalancer.server.port: '8000'
      # pullio
      org.hotio.pullio.notify: 'true'
      org.hotio.pullio.update: 'true'
      # traefik-cloudflare-companion
      cloudflare: 'auto'
    ports:
      - '8340:8000'
    volumes:
      - '{{ DOCKER_DIR }}/2fauth:/2fauth'
    restart_policy: unless-stopped

Get a blank screen if trying localhost:8340, and page not found if going via reverse proxy url (have tried changing app/asset url to 2fauth:8340, etc). Traefik reports all is good (see added screens), so not sure what is going on.

Screenshot 2024-06-24 201630 Screenshot 2024-06-24 201658 Screenshot 2024-06-24 201728a

Log doesn't really tell me much. 2fauth is latest release (5.2.0)

Screenshot 2024-06-24 215012

Bubka commented 2 months ago

@Lebowski89 Is there any error in browser devTools? Check the js files url in the Network tab, does the url domain match the domain visible in the browser address bar?

kamicater commented 2 months ago

I have the same issue, but ASSET_URL did not help.

APP_URL = http://localhost ASSET_URL = http://localhost (just added, wasn't there before)

I also tried the server's IP and its domain name (with and without .lan).

I also added the port with http://localhost:8001 for both _URL parameters, according to your https://github.com/Bubka/2FAuth/issues/340#issuecomment-2162814592 above. But I removed it since I use the latest tag of the container.

I don't use a proxy. I created the container with Portainer inside a Proxmox VM with the default bridge network. I started with version 5.0.3. IIRC I had some problems with blank pages from the beginning, but I was able to overcome them somehow (page refresh?). Then eventually Watchtower hit and I got the latest version.

The issue persists, no matter which address I go to:

with the ASSET_URL respectively changed.

The files exist:

root@myserver:~# docker container exec -it 2fauth /bin/ash
/srv $ ls -la /srv/public/build/assets/app*
-rw-rw-rw-    1 1000     1000        292995 May 29 14:27 /srv/public/build/assets/app-BsP-5XS6.js
-rw-rw-rw-    1 1000     1000        274743 May 29 14:27 /srv/public/build/assets/app-DENUQqjX.css

The browser tells this (e.g. with the IP approach):

2fauth_blank_page

(I don't know why provisional headers are shown despite the cache being disabled)

I think I've tried a few options and it's just a matter of finding the right combination.

What do you think? Anything I can try? Some of your comments refered to previous versions. It would be nice if you could give some updated hints about the current version 5.2.0 only. Thank you for your time.

Bubka commented 1 month ago

Please do not set ASSET_URL with v5.0.4 or higher (unless you want to serve the js|css files from another server, i.e from a CDN). The APP_URL will be used as a fallback value, this eases the configuration process.

If the docker container is mapped to a specific port, then add it to the APP_URL value.

Once done, reload the 2FAuth index in your browser (use ctrl+F5 to force cache clearing). If you get the blank page, check the Network tab in Dev Tools: Is the domain of the app-BsP-5XS6.js request url the same as the domain in the browser address bar ? It should.

In a nutshell:

... and so on. This is to avoid cors error.

If the blank page persists despite this tuning then maybe APP_URL is not the problem. What kind of error the Dev Tools returns for the js/css requests?

kamicater commented 1 month ago

Thanks, that worked! :) All I had to do was to add the port to APP_URL. I deleted ASSET_URL, it wasn't there in the first place.

I'd like to suggest that you add another note for APP_URL in the doc. Something like "Ensure you add :<portnumber> inside APP_URL. It must match the same location as your browsers address bar in most cases."

Bubka commented 1 month ago

Thanks for the suggestion, I've changed the documentation to reflect this, the website will be updated soon.