I'm local on Mac OS 10.14.6 using Angular 8, Symfony 4.3 and mercure 0.72 darwin. I'm quite new to symfony. I wanted to dispatch updates only to authorized clients on my local machine. So far it really is a big pain. I hope I can find some help or answers here.
Last error I get is
http: TLS handshake error from ip:55289: acme/autocert: unable to authorize "mydyndns-url.com"; challenge "http-01" failed with error: acme: authorization error for mydyndns-url.com: 400 urn:acme:error:connection: Fetching http://mydyndns-url.com/.well-known/acme-challenge/SomeHash: Error getting validation data; challenge "tls-alpn-01" failed with error: acme: authorization error for mydyndns-url.com: 400 urn:acme:error:connection: Connection refused
plus
http: TLS handshake error from ip:56803: acme/autocert: missing certificate
I have no remote server on which I could test anything.
But I want to dispatch some updates to authorized clients. Is there no way for me to test this locally ? without any sll tls stuff ?
So far if I understand correctly, to use authorization in clients (cookie or bearer) I must have encrypted mercure communication, for that I need a certificate, which I created with letsencrypt for my dyndns url, which I also just created for that, but then also I read that for the authorization with encrypt all must run on 443, but all is on one machine, so do I need to create subdomains for all my local test servers now ? (because there's a problem with my dyndns on certificate creation using sudo certbot certonly --standalone
, it gives me Challenge failed for my sub domains, being then sub sub domains of the dyndns provider), then also why does he try to fetch a :80 server for the authorization with the .well-known path ?
But because I feel like I went down alices rabbithole and that it has no end, I don't know if it even makes anymore sense to try anything with mercure.
I just want to push a message on '/messages' to target '/user/patata' and then get that message in my angular client autherized using a cookie. Is it so hard to do that on a local development server ? Is there some complete doc for that use case?
Using this to launch mercure
sudo PUBLISHER_JWT_KEY='mercure_key' SUBSCRIBER_JWT_KEY='mercure_key' JWT_KEY='mercure_key' ACME_HOSTS='mydyndns-url.com' ADDR='mydyndns-url.com:443' CERT_FILE='/Users/me/Projects/fullchain.pem' KEY_FILE='/Users/me/Projects/privkey.pem' CORS_ALLOWED_ORIGINS='*' ALLOW_ANONYMOUS='1' debug='1' ./mercure
Of course theres also the symfony settings and code and angular code and so forth. But that would be too much to put everything in here. And mostly I'd like to know how to uncomplicate this, not to make you dizzy as well :D
OK, I managed to solve it (not perfect yet, but running, and it's for development only anyway).
composer require symfony/mercure-bundle
fritzbox
) to forward port 80 and 443
http. (temporarily, for the certbot certificate creation only !!!)sudo ifconfig lo0 alias [public IP] up
(client.mydomain.dynu.org,api.mydomain.dynu.org,hub.mydomain.dynu.org)
bound to my public IP.sudo certbot certonly --standalone
and created one cert for 4 domains (client.mydomain.dynu.org,api.mydomain.dynu.org,hub.mydomain.dynu.org,mydomain.dynu.org)
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
api.
and the angular client.
subdomains (I don't use symfony server:start
)<VirtualHost api.mydomain.dynu.org:443>
DocumentRoot "/Users/me/Sites/api/public"
ServerName api.mydomain.dynu.org
SSLEngine on
SSLCertificateFile "/Users/me/Projects/mydomain.dynu.org.crt"
SSLCertificateKeyFile "/Users/me/Projects/mydomain.dynu.org.key"
ErrorLog "/Users/me/Sites/api/error_log"
CustomLog "/Users/me/Sites/api/access_log" common
</VirtualHost>
<VirtualHost client.mydomain.dynu.org:443>
ServerName client.mydomain.dynu.org
SSLEngine On
SSLProxyEngine On
ProxyRequests Off
SSLCertificateFile "/Users/me/Projects/mydomain.dynu.org.crt"
SSLCertificateKeyFile "/Users/me/Projects/mydomain.dynu.org.key"
ProxyPass / http://client.mydomain.dynu.org:444/
ProxyPassReverse / http://client.mydomain.dynu.org:444/
</VirtualHost>
<VirtualHost hub.mydomain.dynu.org:443>
ServerName hub.mydomain.dynu.org
SSLEngine On
SSLProxyEngine On
ProxyRequests Off
SSLCertificateFile "/Users/me/Projects/mydomain.dynu.crt"
SSLCertificateKeyFile "/Users/me/Projects/mydomain.dynu.key"
ProxyPass / http://hub.mydomain.dynu.org:445/
ProxyPassReverse / http://hub.mydomain.dynu.org:445/
</VirtualHost>
in '.env':
MERCURE_PUBLISH_URL=https://hub.mydomain.dynu.org:443/hub
CORS_ALLOW_ORIGIN=^https://client.mydomain.dynu.org$
in 'nelmio_cors.yaml':
nelmio_cors:
defaults:
...
origin_regex: true
paths:
...
'^/api/':
allow_origin: ['^https://client.mydomain.dynu.org']
allow_headers: ['Content-Type', 'Authorization']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']
max_age: 3600
...
In angular I'm using EventSourcePolyfill like described here https://www.npmjs.com/package/event-source-polyfill to transmit the Bearer token but needed to change the source file to have EventSourcePolyfill bound to the global (it's window) variable, because I just don't know how to handle these non .ts files better up till now. (maybe someone can provide a real solution)
The token I generate in symfony
$username = $this->getUser()->getUsername(); // Retrieve the username of the current user
$token = (new Builder())
// set other appropriate JWT claims, such as an expiration date
->withClaim('mercure', ['subscribe' => ["/user/patata"], 'publish' => ['*']]) // could also include the security roles, or anything else
->sign(new Sha256(), 'mercure_key') // don't forget to set this parameter! Test value: aVerySecretKey
->getToken();
$response = $this->json(['token' => sprintf('%s', $token)]);
I run angular on port 444 sudo ng serve --host client.mydomain.dynu.org --port 444
, the apache reverse proxy forwards all requests on 443 to that
I launch mercure using
sudo PUBLISHER_JWT_KEY='mercure_key' SUBSCRIBER_JWT_KEY='mercure_key' \
JWT_KEY='mercure_key' ADDR='hub.mydomain.dynu.org:445' \
CORS_ALLOWED_ORIGINS='*' ALLOW_ANONYMOUS='1' DEBUG='1' ./mercure
Follow all this above with care: - I'm quite new to symfony, always used flowframework before. - I never had to deal with setup or config of certificates before - And I never had to deal with any encryption setup, no JWT, no apache reverse proxy.
History:
I tried the mercure cookie token way before, buuut it didn't work and somewhere was written that you need encryption enabled for that, so that meant a certificates-way for me, but self generated didn't help and instead I read about using letsencrypt, so I went that way, till somewhere I read that letsencrypt only runs on 443 and so I read about proxies and went that way, not sure if it really had to be that way.
Right now I would have new ideas without the certificates and stuff, which I'd try at the beginning, but everything runs now and I can develop again and that's all I wanted. And on that way I learned how to create letsencrypt certs, about reverse proxies and what acme is meant for :D.
But if you have any suggestions, complaints, warnings, improvements, please let me know !!