HTTP/2 server pushed assets fail to load (HTTP2_CLIENT_REFUSED_STREAM) - laravel

I have the following error ERR_HTTP2_CLIENT_REFUSED_STREAM in chrome devtools console for all or some of the assets pushed via http2.
Refreshing the page and clearing the cache randomly fixes this issue partially and sometimes completely.
I am using nginx with http2 enabled (ssl via certbot) and cloudflare.
server {
server_name $HOST;
root /var/www/$HOST/current/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
set $auth "dev-Server.";
if ($request_uri ~ ^/opcache-api/.*$){
set $auth off;
}
auth_basic $auth;
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
location ~* \.(?:css|js)$ {
access_log off;
log_not_found off;
# Let laravel query strings burst the cache
expires 1M;
add_header Cache-Control "public";
# Or force cache revalidation.
# add_header Cache-Control "public, no-cache, must-revalidate";
}
location ~* \.(?:jpg|jpeg|gif|png|ico|xml|svg|webp)$ {
access_log off;
log_not_found off;
expires 6M;
add_header Cache-Control "public";
}
location ~* \.(?:woff|ttf|otf|woff2|eot)$ {
access_log off;
log_not_found off;
expires max;
add_header Cache-Control "public";
types {font/opentype otf;}
types {application/vnd.ms-fontobject eot;}
types {font/truetype ttf;}
types {application/font-woff woff;}
types {font/x-woff woff2;}
}
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/$HOST/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/$HOST/privkey.pem; # managed by Certbot
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = $HOST) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name $HOST;
listen 80;
return 404; # managed by Certbot
}
Googling this error doesn't return much results and if it helps, it's a laravel 6 app that pushes those assets, if i disable assets pushing in laravel, then all assets load correctly.
I don't even know where to start looking.
Update 1
I enabled chrome logging, and inspected the logs using Sawbuck, following the instructions provided here and found that the actual error has some relation with a 414 HTTP response, which implies some caching problem.
Update 2
I found this great The browser can abort pushed items if it already has them which states the following:
Chrome will reject pushes if it already has the item in the push cache. It rejects with PROTOCOL_ERROR rather than CANCEL or REFUSED_STREAM.
it also links to some chrome and mozilla bugs.
Which led me to disable cloudflare completely and test directly with the server, i tried various Cache-Control directives and also tried disabling the header, but the same error occures, upon a refresh after a cache clear.
Apparently, chrome cancel the http/2 pushed asset even when not present in push cache, leaving the page broken.
For now, i'm disabling http/2 server push in laravel app as a temporary fix.

We just got the exact same problem you're describing. We got "net::ERR_HTTP2_CLIENT_REFUSED_STREAM" on one of our Javascript files. Reloading and clearing cache worked but then the problem came back, seemingly randomly. The same issue in Chrome and Edge (Chromium based). Then I tried in Firefox and got the same behavior but Firefox complained that the response for that url was "text/html". My guess is that for some reason we had gotten a "text/html" response cached for that url in Cloudflare. When I opened that url directly in Firefox I got "application/javascript" and then the problem went away. Still not quite sure how this all happened though.
EDIT:
In our case it turned out that the response for a .js file was blocked by the server with a 401 and we didn't send out any cache headers. Cloudflare tries to be helpful because the browser was expecting a .js file so the response was cached even if the status was 401. Which later failed for others because we tried to http2 push a text/html response with status 401 as a .js file. Luckliy Firefox gave us a better, actionable error message.
EDIT2:
Turns out it wasn't a http header cache issue. It was that we had cookie authentication on .js files, and it seems that the http2 push requests doesn't always include cookies. The fix was to allow cookieless requests on the .js files.

For anyone who comes here using Symfony's local development server (symfony server:start), I could not fix it but this setting (which is the default setting) stops the server to try to push preloaded assets and the error goes away:
config/packages/dev/webpack_encore.yaml
webpack_encore:
preload: false

Related

CloudFlare Invalid SSL certificate

I have a Laravel 8 application.
I have no idea what I missed. I'm trying to deploy a site in my server.
I kept getting :
Invalid SSL certificate
https://mybabies.app/
server {
listen 443;
ssl_certificate /etc/nginx/ssl/mybabies.app.crt;
ssl_certificate_key /etc/nginx/ssl/mybabies.app.key;
server_name mybabies.app www.mybabies.app;
root /home/bheng/mybabies/public;
index index.html index.htm index.php;
charset utf-8;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
client_max_body_size 500M;
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log error;
error_page 404 /index.php;
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|mp3|ogg|ogv|webm|htc|woff2|woff)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1y;
access_log off;
add_header Cache-Control "public";
}
location / {
#limit_req zone=one burst=2 nodelay;
try_files $uri $uri/ /index.php?$query_string;
add_header 'Access-Control-Allow-Origin' '*';
}
}
I already create crt + pem key in CloudFlare and configure in these 2 lines :
ssl_certificate /etc/nginx/ssl/mybabies.app.crt;
ssl_certificate_key /etc/nginx/ssl/mybabies.app.key;
Edit
When I paused it
When I clicked View Certificate, I see
Updated
I created the cert from
To setup secure connection between Cloudflare and your server you need to generate Origin CA Certificate in page Origin Certificates, but you did this in Client Certificates instead, so that's why you are getting error.
They are completelly different things with different purpose. Read descriptions.
Client Certificates
Secure and authenticate your APIs and web
applications with client certificates. Block traffic from devices that
do not have a valid client SSL/TLS certificate with mTLS rules.
Origin Certificates
Generate a free TLS certificate signed by Cloudflare to install on
your origin server. Origin Certificates are only valid for encryption
between Cloudflare and your origin server.
After generating PEM an KEY you need to put them in .crt and .key and load in nginx config, like you did before.
listen 443;
ssl_certificate /etc/nginx/ssl/mybabies.app.crt;
ssl_certificate_key /etc/nginx/ssl/mybabies.app.key;
Now connection Full (strict) should work.
If you want to use self-signed certificate instead, but still leverage secure connection between CF and server, then use option Full instead (without strict). By using Flexible your visitor will be still using HTTPS, but there will be no SSL connection between CF and server, and server will see this as HTTP connection, so this option is not recommended.
Rad more: https://support.cloudflare.com/hc/en-us/articles/200170416-What-do-the-SSL-options-mean-

Nginx Server Configuration: Hostname not resolving on Subdomain

thank you in advance for your support.
I set up an Ubuntu Server with Nginx as a Digitalocean Droplet and am using the server provisioning tool Laravel Forge, which works fine. I successfully installed the PHP Framework Laravel and deployed the code on the server. I ssh into the server and checked the files in the supposed directory. The code is successfully deployed.
Next I own a domain, and created an A record for the following subdomain: app.mywebsite.de, that points to that server. I followed the digitalocean instructions and I waited the required time. Using a DNS Lookup tool, I confirmed that the subdomain actually points to the server.
Screenshot of DNS Lookup
Yet, when I use the subdomain in my browser, the browser doesn't connect to the server. I get the following error message in the browser:
Screenshot of Browser when connecting to server
It seems like the subdomain is correctly pointed to the server, but the server isn't rightly configured. I tried to check the nginx configuration and under sites-avaialble I have the following configuration for the subdomain:
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/app.mywebsite.de/before/*;
server {
listen 80;
listen [::]:80;
server_name app.mywebsite.de;
server_tokens off;
root /home/forge/app.mywebsite.de/public;
# FORGE SSL (DO NOT REMOVE!)
# ssl_certificate;
# ssl_certificate_key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS_AES_256_GCM_SHA384:TLS-AES-256-GCM-SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/app.mywebsite.de/server/*;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/app.mywebsite.de-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/app.mywebsite.de/after/*;
In forge-conf/app.website.de/before/*; is only one file redirect.conf with the following code:
server {
listen 80;
listen [::]:80;
server_name www.app.website.de;
if ($http_x_forwarded_proto = 'https') {
return 301 https://app.website.de$request_uri;
}
return 301 $scheme://app.website.de$request_uri;
}
There are no other sites on the server. So there is only the 000-catch-all file in the sites available directory of the nginx configuration folder.
Unfortunately I reached my limit of understanding here and I would love if somebody could point me into the right direction to find out, which part of nginx is not configured corectly.
P.S.
Some additional info:
Yes I restarted Nginx and the whole server multiple times.
Turns out, everything was configured correctly. I didn't change anything, except that I added some additional sites on the nginx server. Forge probably updated the server blocks, which resolved the problem.

Redirect from Http to https issue in NGINX Google Compute Engine

We already tried other solutions on Stack Overflow but they didn't work for us.
We are having issues while redirecting our Domain url from http to https.
When we hit the http://example.com, it is not getting redirected to https://example.com. We have also set up a Google Managed SSL in the Load Balancer in our Google Cloud Network Service.
We are using the Google Cloud Compute Engine for hosting the website and Google domains for url. Apart from that we are using the NGINX as our web server and Laravel as our framework. We also contacted the Google support team but couldn't worked.
Front and Backend Load Balancer Configuration:
PHP Framework - Laravel V8
Compute Engine - Debian 10 Buster
Below is the code for NGINX config file.
NGINX Default Config file
server
{
listen 80;
server_name example.in www.example.in;
root /var/www/html/test;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
So the below configuration really solved my issue .
I just added a new Port 80 (Http) configuration in my Front End configuration of my Load Balancer along with the Port 443 (Https) .
Now the Domain URL is getting redirected from http to https with secure connections.
Please refer to the below Screenshot of my Load Balancer Frontend Configuration .
Thank you #JohnHanley for your answer ;)
I think your NGINX configuration needs to adjust to listen on port 443 and you need to get the SSL certificate accordingly.
Please refer : https://cloud.google.com/community/tutorials/https-load-balancing-nginx.

laravel email verify not works in production because of ssl certificate

User must verify their email address so I use laravel email verification.
I configured the project on Ubuntu20.04 and with nginx. Verification link works when I use let's encrypt certificate.
I followed all the steps and configured cloudflare and I followed digitalocean tutorial for adding cloudflare ssl certificate.
This is the nginx configuration for domain
server {
listen 80;
listen [::]:80;
server_name ishtap.az www.ishtap.az;
return 302 https://$server_name$request_uri;
}
server {
# listen 80;
# ssl(created in cloudflare) configuration follwing digitalocean tutorial
# https://www.digitalocean.com/community/tutorials/how-to-host-a-website-using-cloudflare-and-nginx-on-ubuntu-20-04
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
ssl_client_certificate /etc/ssl/cloudflare.crt;
ssl_verify_client on;
server_name ishtap.az www.ishtap.az;
root /var/www/ishtap.az/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
# listen 443 ssl; # managed by Certbot
# ssl_certificate /etc/letsencrypt/live/ishtap.az/fullchain.pem; # managed by Certbot
# ssl_certificate_key /etc/letsencrypt/live/ishtap.az/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
}
So when I click email verification link I get error in the attached
image. If cloudflare paused it works no problem but at some route like
where you input sensitive data like password chrome not makes request
and throws "your connection to this site is not fully secured"
In this case, you will have to repair the certificate since the certificate chain is unable to see where is the exact location or the cert is unable to be decrypted. In other words, you can use this tool
To use this tool, you will have to use a Windows machine.
This tool is from DigiCert, you can open it and you can click on SSL, and you can select the cert and click on repair. Also, you can create a new CSR, and you can reissue the cert once again to be able to upload it one more time to your server.
Let me know if you have any other questions or concerns, and I would be more than happy to help you.
The email verification notification is sent in queue and I use supervisor in ubuntu. I find out that there is something wrong with laravel .env file
This is the steps:
fixed APP_URL in .env file to https version of domain
php artisan cache:clear
php artisan config:clear
sudo systemctl reload nginx
php artisan config:cache
supervisorctl restart all restarts all workers

Laravel Glide - 404 Accessing Images: NGINX Cache Issue

Within my Laravel 5.1 app, I'm using https://github.com/thephpleague/glide to resize and serve images via a .cache directory once resized. I am running into the exact same issue as Laravel Glide not finding images at urls with extension
Have had to disable caching in NGINX:
# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
expires -1;
access_log logs/static.log;
}
# Feed
location ~* \.(?:rss|atom)$ {
expires 1h;
add_header Cache-Control "public";
}
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1y;
access_log off;
add_header Cache-Control "public";
}
# WebFonts
# If you are NOT using cross-domain-fonts.conf, uncomment the following directive
location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
After disabling these rules I can access the images again. Any tips? I can still "see" the images when enabling this, but my server cannot read them. A little lost on what could be going on here. Thanks for any help!
Take 'jpg|jpeg|gif|png|' out of your matches, restart nginx, clear browser cache. Glide will sort the caching out for your images.

Resources