Unable to setup Mercure with docker and Nginx(404 Not Found)

Hi!

I’m trying to setup a project with Mercure. My project is a symfony for 7 version.
In that project, only mercure is setting up with docker, but the rest of the application, like nginx, database or symfony are not in docker. After tring many solution, i was not be able to found out the solution. Actualy with my setup, i get a 404 Not found error (response by nginx and not symfony)> Here is my code:

docker-compose.yml:

 # - ./docker/db/data:/var/lib/postgresql/data:rw
###< doctrine/doctrine-bundle ###

###> symfony/mercure-bundle ###
  mercure:
    image: dunglas/mercure
    restart: unless-stopped
    container_name: flex_mercure
    ports:
      -  "3000:3000"
    environment:
      SERVER_NAME: ':3000'
      MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
      MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
      # Set the URL of your Symfony project (without trailing slash!) as value of the cors_origins directive
      MERCURE_EXTRA_DIRECTIVES: |
        cors_origins https://flex-test.xyz
        use_forwarded_headers "1"
    # Comment the following line to disable the development mode
    #command: /usr/bin/caddy run --config /etc/caddy/Caddyfile.dev
    volumes:
      - mercure_data:/data
      - mercure_config:/config
###< symfony/mercure-bundle ###

volumes:
###> doctrine/doctrine-bundle ###
  #database_data:
###< doctrine/doctrine-bundle ###

###> symfony/mercure-bundle ###
  mercure_data:
  mercure_config:
###< symfony/mercure-bundle ###

My .env

###> symfony/mercure-bundle ###
# See https://symfony.com/doc/current/mercure.html#configuration
# The URL of the Mercure hub, used by the app to publish updates (can be a local URL)
MERCURE_URL=http://127.0.0.1/mercure/.well-known
# The public URL of the Mercure hub, used by the browser to connect
MERCURE_PUBLIC_URL=http://127.0.0.1/mercure/.well-known
# The secret used to sign the JWTs
MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
###< symfony/mercure-bundle ###

and my nginx config:

    # /etc/nginx/conf.d/example.com.conf
server {
    listen 80;
    server_name flex-test.xyz;
    root /var/www/flex/flex-v2/public;

    location / {
        # try to serve file directly, fallback to index.php
        try_files $uri /index.php$is_args$args;
    }

    location /mercure/.well-known {
        proxy_pass http://127.0.0.1:3000/mercure/.well-known;
        proxy_read_timeout 24h;
        proxy_http_version 1.1;
        proxy_set_header Connection "";

        ## Be sure to set USE_FORWARDED_HEADERS=1 to allow the hub to use those headers ##
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;

        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;

        internal;
    }


    # optionally disable falling back to PHP script for the asset directories;
    # nginx will return a 404 error when files are not found instead of passing the
    # request to Symfony (improves performance but Symfony's 404 page is not displayed)
    # location /bundles {
    #     try_files $uri =404;
    # }

    #location ~ ^/index\.php(/|$) {
        # when using PHP-FPM as a unix socket
        #fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;

        # when PHP-FPM is configured to use TCP
        # fastcgi_pass 127.0.0.1:9000;

        #fastcgi_split_path_info ^(.+\.php)(/.*)$;
        #include fastcgi_params;

        # when PHP-FPM is configured to use TCP
        # fastcgi_pass 127.0.0.1:9000;

        #fastcgi_split_path_info ^(.+\.php)(/.*)$;
        #include fastcgi_params;

        # optionally set the value of the environment variables used in the application
        # fastcgi_param APP_ENV prod;
        # fastcgi_param APP_SECRET <app-secret-id>;
        # fastcgi_param DATABASE_URL "mysql://db_user:db_pass@host:3306/db_name";

        # When you are using symlinks to link the document root to the
        # current version of your application, you should pass the real
        # application path instead of the path to the symlink to PHP
        # FPM.
        # Otherwise, PHP's OPcache may not properly detect changes to
        # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
        # for more information).
        # Caveat: When PHP-FPM is hosted on a different machine from nginx
        #         $realpath_root may not resolve as you expect! In this case try using
        #         $document_root instead.
        #fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        #fastcgi_param DOCUMENT_ROOT $realpath_root;
        # Prevents URIs that include the front controller. This will 404:
        # http://example.com/index.php/some-path
        # Remove the internal directive to allow URIs like this
        #internal;
    #}

    # return 404 for all other php files not matching the front controller
    # this prevents access to other php files you don't want to be accessible.
    location ~ \.php$ {
        return 404;
    }

    error_log /var/log/nginx/flex_error.log;
    access_log /var/log/nginx/flex_access.log;


    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/flex-test.xyz/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/flex-test.xyz/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}



server {
    if ($host = flex-test.xyz) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    server_name flex-test.xyz;
    listen 80;
    return 404; # managed by Certbot


}

Thank for any help !

Not sure if those lines work. Server name with : and MERCURE_EXTRA_DIRECTIVES with a linebreak.

Hi, thank you for your reply. I have completly remove MERCURE_EXTRA_DIRECTIVES by adding comment on it, but i still get 404 Not found(Responding by Nginx, not symfony itself). Any other suggestions ?

I have additinal information. When i make a cur request on localhost with port 3000, it return me the mercure welcome page. That mening that the mercure hub is correctly setting up, but it look like my problem is with nginx and my .env file.

curl 127.0.0.1:3000

Welcome to Mercure

Welcome to Mercure

The URL of your hub is /.well-known/mercure. Read the documentation on Mercure.rocks, real-time apps made easy.

Thank for any idea

I am afraid we will need way more information, if you don’t want to wait for someone who actually used mercure. I don’t even know what it is, but it appears to be an oidc idp of some sorts.

Please share a diagram that shows all involved components, whether they run on the host, inside a container, or somewhere else in the network and how the communication flow between the components should look like.

Hello Every One. I finaly found the solution. The Problem was the url for mercure in my .env and my nginx config. So i would explain. The url using by the mercure hub internaly is /.well-known/mercure, so and other url will not work. That wy in my Nginx config, in the proxy pass, i have use localhost:3000/.well-known/mercure, and the same url in my env (MERCURE_URL = http:://localhost:3000/.well-known/mercure and the public mercure url for the broswer tho connect https://mydomain.xyz/.well-known/mercure) as you can see below:

Nginx conf


     # Configuration for Mercure service
    location /mercure {
        proxy_pass http://localhost:3000; # URL du service Mercure
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 10s;
        proxy_send_timeout 10s;
        proxy_read_timeout 10s;
    }

    # Configuration for  the route /.well-known/mercure
    location /.well-known/mercure {
        proxy_pass http://localhost:3000/.well-known/mercure;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 10s;
        proxy_send_timeout 10s;
        proxy_read_timeout 10s;
    }

.env config


###> symfony/mercure-bundle ###
MERCURE_URL=http://localhost:3000/.well-known/mercure
MERCURE_PUBLIC_URL=https://flex-test.xyz/.well-known/mercure
MERCURE_JWT_SECRET='!ChangeThisMercureHubJWTSecretKey!'
MERCURE_PUBLISHER_JWT_KEY='!ChangeThisMercureHubJWTSecretKey!'
MERCURE_SUBSCRIBER_JWT_KEY='!ChangeThisMercureHubJWTSecretKey!'
###< symfony/mercure-bundle ###



version: '3'

services:
###> doctrine/doctrine-bundle ###
  #database:
  # image: postgres:${POSTGRES_VERSION:-15}-alpine
  #  environment:
  #    POSTGRES_DB: ${POSTGRES_DB:-app}
      # You should definitely change the password in production
  #    POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
  #    POSTGRES_USER: ${POSTGRES_USER:-app}
  #  volumes:
  #    - database_data:/var/lib/postgresql/data:rw
      # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your d>
      # - ./docker/db/data:/var/lib/postgresql/data:rw
###< doctrine/doctrine-bundle ###

###> symfony/mercure-bundle ###
  mercure:
    image: dunglas/mercure
    restart: unless-stopped
    container_name: flex_mercure
    ports:
      -  "3000:3000"
    environment:
      SERVER_NAME: ':3000'
      MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
      MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
      # Set the URL of your Symfony project (without trailing slash!) as value of the cors_origins directive
      MERCURE_EXTRA_DIRECTIVES: |
        cors_origins *
        anonymous
        #use_forwarded_headers "1"
    # Comment the following line to disable the development mode
    #command: /usr/bin/caddy run --config /etc/caddy/Caddyfile.dev
    volumes:
      - mercure_data:/data
      - mercure_config:/config
###< symfony/mercure-bundle ###

volumes:
###> doctrine/doctrine-bundle ###
  #database_data:
###< doctrine/doctrine-bundle ###

###> symfony/mercure-bundle ###
  mercure_data:
  mercure_config:
###< symfony/mercure-bundle ###

Hop it can help some body one day… :slightly_smiling_face: