platformsh / mercure-rocks-example

1 stars 1 forks source link

Update to the latest mercure version? #1

Open yobottehg opened 2 years ago

yobottehg commented 2 years ago

This guide is for a legacy version of Mercure.

The latest Mercure comes bundled with a caddy webserver.

I tried to get this up and running but ran into a problem at the end. Perhaps this guide can be upgraded to the latest version of Mercure?

I'm trying to set this up together with a symfony (api-platform) application and a Nuxt.js consumer.

What is working:

What is not working: Dispatching updates to the client via the open EventSource stream. The updates are delivered to the client but only after the write_timeout of the caddy webserver. The default config for write_timeout is 600s. When i lower this to 5s then the update from the Mercure hub is delivered after 5s and the client is reconnecting after that which is not suitable?

The config value can be found here: https://mercure.rocks/docs/hub/config

Another thing i found is that the proposed config for the nginx reverse proxy in front of the caddy can be found here: https://mercure.rocks/docs/hub/cookbooks

What is confusing is this setting here proxy_http_version 1.1;

lando locally is using http 1.1, platform.sh is http 2 --> This could also be the problem?

Here is what i tried (This is after several hours of trying different things):

applications.yaml:

-   name: mercure
    type: golang:1.18
    disk: 1024
    source:
        root: mercure
    hooks:
        build: |
            MERCUREVERSION=0.13.0
            FILE="mercure_${MERCUREVERSION}_Linux_x86_64.tar.gz"
            URL="[https://github.com/dunglas/mercure/releases/download/v${MERCUREVERSION}/$FILE](https://github.com/dunglas/mercure/releases/download/v$%7BMERCUREVERSION%7D/$FILE)"
            if [ ! -f "$PLATFORM_CACHE_DIR/$FILE" ]; then
                wget -O "$PLATFORM_CACHE_DIR/$FILE" $URL
            fi
            tar xzf $PLATFORM_CACHE_DIR/$FILE
            mv Caddyfile_prod Caddyfile
    variables:
        env:
            MERCURE_PUBLISHER_JWT_KEY: '!ChangeMe!'
            MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeMe!'
            SERVER_NAME: ':8888'
    mounts:
        "database":
            source: local
            source_path: "database"
        ".config":
            source: local
            source_path: ".config"
    web:
        commands:
            start: ./mercure run
        locations:
            /:
                allow: false
                passthru: true

Caddyfile_prod:

{
    auto_https off
}

{$SERVER_NAME:localhost}

log

route {
    mercure {
        transport_url {$MERCURE_TRANSPORT_URL:bolt:///app/database/mercure.db}
        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        publish_origins *
        anonymous
        subscriptions
        {$MERCURE_EXTRA_DIRECTIVES}
    }

    respond "Not Found" 404
}

Routes.yaml:

"https://mercure/.{default}/":
    type: upstream
    upstream: "mercure:http"
    id: 'mercure'
    cache:
        enabled: false
finnef commented 2 years ago

I came across this issue recently. As Symfony now defaults to using Platform.sh as its cloud provider I requested the mercure hub be made available as a standard Platform Service. Until that happens, here is the config I used:

Add Mercure as a separate app in your platform config using this file: .platform/applications.yaml

- name: mercure
  type: golang:1.18
  source:
    root: .platform/mercure
  hooks:
    build: |
      #Install Mercure using cache
      MERCUREVERSION=0.13.0
      FILE="mercure_${MERCUREVERSION}_Linux_x86_64.tar.gz"
      if [ ! -f "$PLATFORM_CACHE_DIR/$FILE" ]; then
          URL="https://github.com/dunglas/mercure/releases/download/v${MERCUREVERSION}/$FILE"
          echo "Downloading $URL"
          wget -O "$PLATFORM_CACHE_DIR/$FILE" $URL
      else
          echo "Found $FILE in cache, using cache"
      fi
      file $PLATFORM_CACHE_DIR/$FILE
      tar xvzf $PLATFORM_CACHE_DIR/$FILE
  variables:
    env:
      SERVER_NAME: ":8888"
      MERCURE_TRANSPORT_URL: "bolt:///var/run/mercure.db"
      MERCURE_EXTRA_DIRECTIVES: |
        cors_origins {$PSH_SITE_URL}
        publish_origins {$PSH_SITE_URL}
      GLOBAL_OPTIONS: |
        auto_https off
  size: S
  disk: 128
  mounts:
    "/.local": { source: local, source_path: .local }
    "/.config": { source: local, source_path: .config }

  web:
    commands:
      start: ./mercure run -config Caddyfile.platformsh
    locations:
      /:
        allow: false
        passthru: true

With this application file you can set the MERCURE_PUBLISHER_JWT_KEY and MERCURE_SUBSCRIBER_JWT_KEY vars using the Platform console (as sensitive vars). The Platform router forwards using http (not https) so the https features won't work out of the box. In the application GLOBAL_OPTIONS I have turned https off for the mercure hub, and in the Caddyfile I manually add the correct headers. The certificate is handled by Platform.

This config needs a root dir (.platform/mercure), and files in that dir: .platform/mercure/.environment

# Statements in this file will be executed (sourced) by the shell in SSH
# sessions, in deploy hooks, in cron jobs, and in the application's runtime
# environment. This file must be placed in the root of the application, not
# necessarily the git repository's root. In case of multiple applications,
# each application can have its own .environment file.

# Expose the main app site url (without trailing /)
export PSH_SITE_URL="$(echo "$PLATFORM_ROUTES" | base64 --decode | jq -r 'to_entries[] | select(.value.upstream=="app") | .key' | awk '{print substr($0, 0, length($0))}')"

This file is executed only for the mercure app because of its separate root dir. The command selects the main app URL for this environment, so you can use this to set an allowed CORS origin for the mercure hub

And the Caddy file: .platform/mercure/Caddyfile.platformsh

# Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
{
    {$GLOBAL_OPTIONS}
}

{$SERVER_NAME:localhost}

log

#cors
header Access-Control-Allow-Origin {$PSH_SITE_URL}
header Access-Control-Allow-Credentials true

route {
    redir / /.well-known/mercure/ui/
    encode zstd gzip

    mercure {
        # Transport to use (default to Bolt)
        transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
        # Publisher JWT key
        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        # Subscriber JWT key
        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        # Extra directives
        {$MERCURE_EXTRA_DIRECTIVES}
    }

    respond /healthz 200

    respond "Not Found" 404
}

This is a copy of the default mercure Caddyfile, with the extra header directives added to allow CORS requests.

Lastly you need to add a route for the mercure app: In .platform/routes.yml

"https://mercure.{default}/":
  type: upstream
  upstream: "mercure:http"
  cache:
    enabled: false