Replies: 23 comments 12 replies
|
It's a URL, not a directory in the filesystem. your.domain.com {
mercure {
...
}
}now it's reachable at But it doesn't have a GUI listening there. Please refer to the ui documentation if you need it to test. In case of a Symfony project you'd now only need to set the MERCURE_URL. |
|
I don't have Synfony installed What you mean with |
|
Hi @henderkes , The On the beginning of the example it is mentioned, that the In the |
|
means you subscribe to the topic for changes of the
The |
|
I understand. I guess, I should only the transfer the Und hier tdie Zeile 208: |
For some reason the call is hitting your php_server, not mercure.
You can't use the token from the example for obvious reasons, you need to generate your own according to the Mercure documentation. |
|
I was thinking to use the same password and the same JWT value as it is in the example, to get it easier for testing. If it would working, I would change it in the next step. Can I not do it? To find the problem with php_server and mercure, I think, I have to understand what I have to do, to send it to mercure. Thanks for your help Marc. |
No, that won't work. Even if the example token was valid at the time of writing the documentation, it wouldn't be an hour later anymore. JWT's are not passwords or immutable API keys. You need to sign a jwt using the Usually mercure should automatically be handled before php_server, so I'm not sure on that front. @dunglas any idea? |
|
Please see my comment to your previous message. |
|
I just tried your Caddyfile and Mercure settings (adjusted to localhost) and it's working perfectly fine: ❯❯ symfony-demo git:(main) 18:32 cat Caddyfile
localhost {
root ./public
log
encode zstd br gzip
route {
mercure {
publisher_jwt {$MERCURE_PUBLISHER_JWT_KEY:!ChangeThisMercureHubJWTSecretKey!}
subscriber_jwt {$MERCURE_SUBSCRIBER_JWT_KEY:!ChangeThisMercureHubJWTSecretKey!}
}
php_server
}
}
❯❯ symfony-demo git:(main) 18:32 frankenphp start -c Caddyfile
2026/01/31 17:32:09.634 INFO maxprocs: Leaving GOMAXPROCS=32: CPU quota undefined
2026/01/31 17:32:09.634 INFO GOMEMLIMIT is updated {"package": "github.com/KimMachineGun/automemlimit/memlimit", "GOMEMLIMIT": 30248169062, "previous": 9223372036854775807}
2026/01/31 17:32:09.634 INFO using config from file {"file": "Caddyfile"}
2026/01/31 17:32:09.635 INFO adapted config to JSON {"adapter": "caddyfile"}
2026/01/31 17:32:09.635 WARN Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies {"adapter": "caddyfile", "file": "Caddyfile", "line": 2}
2026/01/31 17:32:09.648 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//[::1]:2019", "//127.0.0.1:2019", "//localhost:2019"]}
2026/01/31 17:32:09.648 INFO http.auto_https server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2026/01/31 17:32:09.648 INFO http.auto_https enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2026/01/31 17:32:09.648 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc000760680"}
2026/01/31 17:32:09.652 INFO pki.ca.local root certificate is already trusted by system {"path": "storage:pki/authorities/local/root.crt"}
2026/01/31 17:32:09.652 INFO pki intermediate expires soon; renewing {"ca": "local", "time_remaining": -1932344.652885874}
2026/01/31 17:32:09.659 INFO pki renewed intermediate {"ca": "local", "new_expiration": "2026/02/07 17:32:09.000"}
2026/01/31 17:32:09.747 INFO frankenphp FrankenPHP started 🐘 {"php_version": "8.5.1", "num_threads": 64, "max_threads": 64}
2026/01/31 17:32:09.749 WARN http HTTP/2 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2026/01/31 17:32:09.749 WARN http HTTP/3 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2026/01/31 17:32:09.749 INFO http.log server running {"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2026/01/31 17:32:09.760 INFO http enabling HTTP/3 listener {"addr": ":443"}
2026/01/31 17:32:09.771 INFO failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 7168 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.
2026/01/31 17:32:09.772 INFO http.log server running {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2026/01/31 17:32:09.772 INFO http enabling automatic TLS certificate management {"domains": ["localhost"]}
2026/01/31 17:32:09.773 INFO autosaved config (load with --resume flag) {"file": "/home/m/.config/caddy/autosave.json"}
2026/01/31 17:32:09.773 INFO serving initial configuration
Successfully started Caddy (pid=4800) - Caddy is running in the background
2026/01/31 17:32:09.776 INFO tls.obtain acquiring lock {"identifier": "localhost"}
2026/01/31 17:32:09.777 INFO tls storage cleaning happened too recently; skipping for now {"storage": "FileStorage:/home/m/.local/share/caddy", "instance": "c8634587-9fb2-421a-bdc9-0abd4a3da1ba", "try_again": "2026/02/01 17:32:09.777", "try_again_in": 86399.99999952}
2026/01/31 17:32:09.777 INFO tls finished cleaning storage units
2026/01/31 17:32:09.778 INFO tls.obtain lock acquired {"identifier": "localhost"}
2026/01/31 17:32:09.778 INFO tls.obtain obtaining certificate {"identifier": "localhost"}
2026/01/31 17:32:09.786 INFO tls.obtain certificate obtained successfully {"identifier": "localhost", "issuer": "local"}
2026/01/31 17:32:09.786 INFO tls.obtain releasing lock {"identifier": "localhost"}
2026/01/31 17:32:09.786 WARN tls stapling OCSP {"identifiers": ["localhost"]}
❯❯ symfony-demo git:(main) 18:32 curl -d 'topic=songs' -d 'data={"foo": "updated Value"}' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdLCJzdWJzY3JpYmUiOlsiaHR0cHM6Ly9leGFtcGxlLmNvbS9teS1wcml2YXRlLXRvcGljIiwie3NjaGVtZX06Ly97K2hvc3R9L2RlbW8vYm9va3Mve2lkfS5qc29ubGQiLCIvLndlbGwta25vd24vbWVyY3VyZS9zdWJzY3JpcHRpb25zey90b3BpY317L3N1YnNjcmliZXJ9Il0sInBheWxvYWQiOnsidXNlciI6Imh0dHBzOi8vZXhhbXBsZS5jb20vdXNlcnMvZHVuZ2xhcyIsInJlbW90ZUFkZHIiOiIxMjcuMC4wLjEifX19.KKPIikwUzRuB3DTpVw6ajzwSChwFw5omBMmMcWKiDcM' -X POST https://localhost/.well-known/mercure -k
2026/01/31 17:32:27.255 INFO http.handlers.mercure Update published {"update": {"id": "urn:uuid:019c151c-fcf6-7279-99c0-653bd918d103", "type": "", "retry": 0, "topics": ["songs"], "private": false}}
2026/01/31 17:32:27.255 INFO http.log.access handled request {"request": {"remote_ip": "::1", "remote_port": "47386", "client_ip": "::1", "proto": "HTTP/2.0", "method": "POST", "host": "localhost", "uri": "/.well-known/mercure", "headers": {"User-Agent": ["curl/8.16.0"], "Accept": ["*/*"], "Authorization": ["REDACTED"], "Content-Length": ["41"], "Content-Type": ["application/x-www-form-urlencoded"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "localhost"}}, "bytes_read": 41, "user_id": "", "duration": 0.001802698, "size": 45, "status": 200, "resp_headers": {"Alt-Svc": ["h3=\":443\"; ma=2592000"], "X-Frame-Options": ["DENY"], "X-Content-Type-Options": ["nosniff"], "X-Xss-Protection": ["1; mode=block"], "Content-Security-Policy": ["default-src 'self'"], "Server": ["Caddy"]}}As an example how you can use your own keys in the console: ❯❯ symfony-demo git:(main) 18:44 export MERCURE_PUBLISHER_JWT_KEY="Bsalasfoi231ijsajifijji231joSAFSAASAAsafasFF"
❯❯ symfony-demo git:(main) 18:45 frankenphp start -c Caddyfile
- snip -
Successfully started Caddy (pid=8112) - Caddy is running in the background
❯❯ symfony-demo git:(main) 18:45 HEADER=$(echo -n '{"alg":"HS256","typ":"JWT"}' | openssl base64 -e -A | tr -d '=' | tr '/+' '_-')
❯❯ symfony-demo git:(main) 18:46 EXP=$(($(date +%s) + 86400))
❯❯ symfony-demo git:(main) 18:46 PAYLOAD=$(echo -n "{\"mercure\":{\"publish\":[\"songs\"]},\"exp\":$EXP}" | openssl base64 -e -A | tr -d '=' | tr '/+' '_-')
❯❯ symfony-demo git:(main) 18:46 SIGNATURE=$(echo -n "$HEADER.$PAYLOAD" | openssl dgst -sha256 -hmac "$MERCURE_PUBLISHER_JWT_KEY" -binary | openssl base64 -e -A | tr -d '=' | tr '/+' '_-')
❯❯ symfony-demo git:(main) 18:46 echo "$HEADER.$PAYLOAD.$SIGNATURE"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsic29uZ3MiXX0sImV4cCI6MTc2OTk2Nzk3MH0.15xU6VA_6jn3QcRrt_-MdOIGdxODsOkgeLQxRp-8Nf8
❯❯ symfony-demo git:(main) 18:46 curl -d 'topic=songs' -d 'data={"foo": "updated Value"}' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsic29uZ3MiXX0sImV4cCI6MTc2OTk2Nzk3MH0.15xU6VA_6jn3QcRrt_-MdOIGdxODsOkgeLQxRp-8Nf8' -X POST https://localhost/.well-known/mercure -k
2026/01/31 17:47:03.922 INFO http.handlers.mercure Update published {"update": {"id": "urn:uuid:019c152a-5d71-7b8f-907d-5e8218b61d94", "type": "", "retry": 0, "topics": ["songs"], "private": false}}
2026/01/31 17:47:03.922 INFO http.log.access handled request {"request": {"remote_ip": "::1", "remote_port": "46446", "client_ip": "::1", "proto": "HTTP/2.0", "method": "POST", "host": "localhost", "uri": "/.well-known/mercure", "headers": {"Accept": ["*/*"], "Authorization": ["REDACTED"], "Content-Length": ["41"], "Content-Type": ["application/x-www-form-urlencoded"], "User-Agent": ["curl/8.16.0"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "localhost"}}, "bytes_read": 41, "user_id": "", "duration": 0.001667541, "size": 45, "status": 200, "resp_headers": {"Content-Security-Policy": ["default-src 'self'"], "Server": ["Caddy"], "Alt-Svc": ["h3=\":443\"; ma=2592000"], "X-Frame-Options": ["DENY"], "X-Content-Type-Options": ["nosniff"], "X-Xss-Protection": ["1; mode=block"]}}
urn:uuid:019c152a-5d71-7b8f-907d-curl -d 'topic=songs' -d 'data={"foo": "updated Value"}' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdLCJzdWJzY3JpYmUiOlsiaHR0cHM6Ly9leGFtcGxlLmNvbS9teS1wcml2YXRlLXRvcGljIiwie3NjaGVtZX06Ly97K2hvc3R9L2RlbW8vYm9va3Mve2lkfS5qc29ubGQiLCIvLndlbGwta25vd24vbWVyY3VyZS9zdWJzY3JpcHRpb25zey90b3BpY317L3N1YnNjcmliZXJ9Il0sInBheWxvYWQiOnsidXNlciI6Imh0dHBzOi8vZXhhbXBsZS5jb20vdXNlcnMvZHVuZ2xhcyIsInJlbW90ZUFkZHIiOiIxMjcuMC4wLjEifX19.KKPIikwUzRuB3DTpVw6ajzwSChwFw5omBMmMcWKiDcM' -X POST https://localhost/.well-known/mercure -k
2026/01/31 17:47:34.126 INFO http.log.access handled request {"request": {"remote_ip": "::1", "remote_port": "46448", "client_ip": "::1", "proto": "HTTP/2.0", "method": "POST", "host": "localhost", "uri": "/.well-known/mercure", "headers": {"Accept": ["*/*"], "Authorization": ["REDACTED"], "Content-Length": ["41"], "Content-Type": ["application/x-www-form-urlencoded"], "User-Agent": ["curl/8.16.0"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "localhost"}}, "bytes_read": 0, "user_id": "", "duration": 0.000129447, "size": 13, "status": 401, "resp_headers": {"X-Xss-Protection": ["1; mode=block"], "Content-Security-Policy": ["default-src 'self'"], "X-Frame-Options": ["DENY"], "X-Content-Type-Options": ["nosniff"], "Content-Type": ["text/plain; charset=utf-8"], "Server": ["Caddy"], "Alt-Svc": ["h3=\":443\"; ma=2592000"]}}
Unauthorized # confirmation that the old example token doesn't work for this secret |
|
Thank you, but I didn't expect, that there is an problem with the Caddyfile. My current problem is, how send a POST message to the Mercure Hub. I think, if I'm able to create the right POST message, I have solved my implementation of the Mercure HUB, hopefully! |
|
I have deleted the old VM and started from the beginning. If I list the PHP extensions with So I guess frankenphp don't know |
|
Sounds like a php code issue. root@b8d68725db0c:/# php-zts mysqli_test.php
Array
(
[id] => 1
[val] => Entry_9953
)
root@b8d68725db0c:/# cat mysqli_test.php
<?php
$mysqli = new mysqli("localhost", "root", "");
if ($mysqli->connect_error) {
die("Connection failed: " . $mysqli->connect_error);
}
$mysqli->query("CREATE DATABASE IF NOT EXISTS test");
$mysqli->select_db("test");
$mysqli->query("CREATE TABLE IF NOT EXISTS random_data (id INT AUTO_INCREMENT PRIMARY KEY, val VARCHAR(50))");
$val = "Entry_" . rand(1000, 9999);
$mysqli->query("INSERT INTO random_data (val) VALUES ('$val')");
$result = $mysqli->query("SELECT * FROM random_data");
while ($row = $result->fetch_assoc()) {
print_r($row);
}
$mysqli->close();
root@b8d68725db0c:/# php-zts mysqli_test.php
Array
(
[id] => 1
[val] => Entry_9953
)Perhaps you forgot to restart frankenphp after installing php-zts-mysqli. |
|
Guten Morgen, |
|
That's just bash commands and output. It shows that mysqli works perfectly fine. |
|
OK, your test program works fine, after deleted the outputs on the beginning and the end. Thanks! Under |
|
I current try to install Composer with GDebi and gete a request for php-json-schema (>= 6.5.1). |
|
That's not an extension. I really can't help you with all these problems as they are unrelated to FrankenPHP. |
|
I cannot help you with that. PHP issues are outside of FrankenPHP's scope. |
|
If the client fires a EventSource: But I got a 401 Unauthorized error. In |
This is the only message I found in Frankenphp about Mercure. It gives me no additional information! I spend a lot of time to looking for a solution, but I haven't found one yet. Thank you for your support! |
|
Sorry, I forgot how to install a additional extension to php-zts: |

Uh oh!
There was an error while loading. Please reload this page.
I have Frankenphp running and enabled Mercure successful. Now I want to use it, but I'm not able to find the place, where Mercure is stored.
Therefore I'm not able to send the client requests to the Mercure Hub.
I can't find /.well-known/mercure anywhere,
All reactions