I want to simultaneously optimize my site for HTTP/2 and HTTP/1.x. For HTTP/2 (and SPDY), since there are no additional round-trips for requests, I'd like to serve my CSS and JS files separately, to gain the benefit of independently caching each file. However, if I only did that, HTTP/1.x clients would suffer from additional round-trips; so for them, I'd like to serve my CSS and JS files concatenated.
Ideally, HTTP/2 users would be served this HTML:
<html>
<head>
<link rel="stylesheet" href="stylesheet-1.css">
<link rel="stylesheet" href="stylesheet-2.css">
</head>
<body>
<script src="script-1.js"></script>
<script src="script-2.js"></script>
</body>
</html>
And HTTP/1.x users would be served this HTML:
<html>
<head>
<link rel="stylesheet" href="all-stylesheets.css">
</head>
<body>
<script src="all-scripts.js"></script>
</body>
</html>
Is it possible to configure nginx to serve different HTML files depending on the client's protocol?
Yes, you can do so via the $server_protocol variable. I would usually recommend to interpolate file locations by variable expansion. But in this case I fear this would leave you open to injection attacks as the content of this variable seems to be copied verbatim from the request line.
There is a solution by exploiting the ngx_http_map_module, though. Assuming your site sits in /srv/www:
map $server_protocol $version {
default "1.1";
"HTTP/2.0" "2.0";
# extra case for any SPDY version
"~SPDY/" "2.0";
}
server {
listen [::]:80;
# The line below requires a working SSL configuration!
listen [::]:443 ssl http2;
server_name example.com
root /srv/www/http-1.1/htdocs;
location / {
root /srv/www/http-$version/htdocs;
try_files $uri $uri/ #fallback;
}
# fallback for HTTP/1.1 files. If this fails as well, we get a 404.
location #fallback {
try_files $uri $uri/ =404;
}
}
This would serve all requests out of /srv/www/http-2.0/htdocs for HTTP/2.0 requests and out of /srv/www/http-1.1/htdocs for all others. If a resource specially crafted for HTTP/2.0 cannot be found, the coresponding file for HTTP/1.1 is being served as a fallback.
Related
I am quite new to NGINX and within this topic it is still very hard for me to find the right buzzwords to have more successful search results. That is why I try to descibe my problem here and maybe some of you can point me in the right direction. For my own personal project I want to set up a website which is composed from several micro services (which have all their own frontend).
My idea was to have one NGINX sever running serving as web server to deliver some kind of HTML which then includes the content of the micro services via server side includes (SSI).
Since the SSI can only include files and local folders as I understand I added some proxy_pass to my local server configuration:
http {
server {
listen 80;
ssi on;
root /usr/share/nginx/html;
location /led-todo {
proxy_pass http://led-todo-frontend:3000/;
}
}
}
So since I have the NGINX and my micro services in the same docker-compose running the URL: http://led-todo-frontend:3000 works.
The issue I am facing now is that when access my index.html page:
<html>
<head>
</head>
<body>
<!--# include virtual="test.html"-->
<!--# include virtual="/led-todo/"-->
</body>
</html>
The index.html content of my micro service is actually included into the above shown html site.
The issue arises when the script tags within my included html content are resolved:
<script src="/static/js/bundle.js">
The browser tries to load them from:
http://localhost:8080/static/js/bundle.js
Instead of:
http://localhost:8080/led-todo/static/js/bundle.js
Which then would again trigger the proxy pass to the correct micro service.
I feel like there should be some parameters to define the root or something so that /static/js/bundle.js is not loaded from localhost:8080 but from localhost:8080/led-todo in the following part of the NGINX configuration:
location /led-todo {
proxy_pass http://led-todo-frontend:3000/;
}
I tried several things I found in the internet here but somehow I am missing the words to describe this issue so that I can find results...
Anyone know how to solve this issue, or know at least some buzzwords I can search for?
This isn't a very elegant solution, but you can try to on-the-fly rewriting that tags content with the ngx_http_sub_module, something like this could work:
location /led-todo/ {
proxy_pass http://led-todo-frontend:3000/;
sub_filter_once off;
# uncomment to do substitution inside CCS or JS content too
# sub_filter_types text/css application/javascript;
sub_filter 'href="/' 'href="/led-todo/';
sub_filter "href='/" "href='/led-todo/";
sub_filter 'src="/' 'src="/led-todo/';
sub_filter "src='/" "src='/led-todo/";
}
I'm configuring nginx to load only static files and I don't know why .css files are interpreted as text/plain - finally browser couldn't load it.
Resource interpreted as Stylesheet but transferred with MIME type text/plain: "http://localhost:13000/styles.css".
when I check response header in web browser of css file:
Content-Type: text/plain
I know that on stack we have a lot of issues with it, I've already read them but still doesn't work.
in html file I've just import css:
<link href="styles.css" rel="stylesheet" type="text/css"/>
my /etc/nginx/nginx.conf is:
worker_processes 1;
events {
worker_connections 512;
}
http {
server {
listen 80;
server_name 0.0.0.0:80;
include /etc/nginx/mime.types;
root /project/app;
location ~* ^.+\.(js|css)$ {
expires 10d;
}
}
}
I tried without any location part or tried with:
location ~ \.css {
add_header Content-Type text/css;
}
In some responses in other threads I saw that this part is required:
default_type application/octet-stream;
include /etc/nginx/mime.types;
I added it in http part and after that in server and then in location, still didn't help me.
Is there anything else what can I do to fix it?
Just in case somebody has the same problem and use docker.
This is key word - I use docker with image nginx:latest which causes problems, I've changed it to nginx:1.14.2 and everything is working fine.
in html, import css:
<link href="styles/styles.css" rel="stylesheet" type="text/css"/>
my nginx.conf configuration:
worker_processes 1;
events {
worker_connections 512;
}
http {
include mime.types;
sendfile on;
server {
listen 80;
server_name 0.0.0.0:80;
root /project/app;
}
}
I solved the issue for myself. The problem on my side was the actual nginx configuration, let me explain.
Not working (before):
my dockerfile contained this line of code: "COPY deployment/nginx.conf /etc/nginx/nginx.conf"
my nginx.conf contained the "http {" part
How I fixed it:
I updated my docker file to: "COPY deployment/nginx.conf /etc/nginx/conf.d/default.conf" (check the new path where I am copying)
my nginx.conf did not contain any more "http {" block and just the "server {" block. (This works because I am adding a new config file).
Voila! Hope it helps! All in all the culprit was where I was copying the config file and the content of my conf file itself.
I had a similar issue once on my testing server. what i found out was that nginx was doing every thing in the right way. The problem was the referencing of the files. The browser could find the resources but could not load them from the described base.
location / { # default base
root /var/www/html/myfiles; # my root folder
try_files $uri /index.html;
include /etc/nginx/mime.types;
}
changed the base to...
location /myfiles { # changed base
root /var/www/html; # default root folder
try_files $uri /index.html;
include /etc/nginx/mime.types;
}
it worked seamlessly
I had this problem.
In order to solve it for both my static javascript and css files was to add type AND uic-remove as followed:
<link rel="stylesheet" uic-remove href="/index.css" type="text/css">
<script uic-remove type="application/javascript" src="./index.js"></script>
Note: The Javascript link was not throwing any warning or error like the css's warning, however it was nonetheless not working either and I thank the heavens that the fix worked for both. Good Luck!
I would like to have an nginx server hosting web applications on the same domain, with different paths.
For example,
http://example.org/booksapp/signin.html should point to the first app,
and http://example.org/shoesapp/signin.html should point to the second app
within my host, I have two folders, one for each app:
/var/webfolder/booksapp and /var/webfolder/shoesapp
my nginx configuration is the following
server {
server_name example.org;
index index.html index.htm;
location /foodapp {
root /var/webfolder;
try_files $uri $uri/ =404;
}
location /shoesapp {
root /var/webfolder;
try_files $uri $uri/ =404;
}
listen [::]:80;
listen 80;
}
This configuration does not work. My browser just shows a blank page when trying to load either web application.
Meanwhile, the nginx log files shows a list of 404 for every resource that the apps are trying to load.
What am I doing wrong?
You have to change your html files to use the right paths.
Your "booksapp" lives at example.org/booksap/, the html pages must load any static resource using that same path.
This is the head section of an example html file. If you deploy this to any of your sites it will not work, nginx can't find "normalize.css" and "styles.css" unless you specify the right path. Right now nginx is acting as a router between the two apps, you can't ask for just a file, you must specify which app.
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<title>sakura demo</title>
<link href="normalize.css" rel="stylesheet" type="text/css">
<link href="styles.css" rel="stylesheet" type="text/css" media="all">
</head>
It should be:
<link href="booksap/normalize.css" rel="stylesheet" type="text/css">
<link href="booksap/styles.css" rel="stylesheet" type="text/css" media="all">
I am trying to setup a Question2Answer website (yoalfaaz.com) on nginx with Ubuntu. Now, the homepage of the website does load but any other page doesn't load correctly. Mostly, when I click for any post on my website, it opens the homepage again and sometimes just breaks the layout.
Here's the sites-available file
server {
listen 80 ;
listen [::]:80 ;
root /var/www/yoalfaaz.com/html;
# Add index.php to the list if you are using PHP
index index.php index.html index.htm index.nginx-debian.html;
server_name yoalfaaz.com www.yoalfaaz.com;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.php$is_args$args;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Now, previously only the homepage was opening and for every other page, I was getting 404 Not Found error. So I made some changes to try_files line and after that, the website pages are not opening in the correct way.
I have also checked for any kind of errors, but there are none and if I try nginx -t then it also shows successful. Please help me out, guys.
Apparently the problem is not nginx, but your application.
Looking at the HTML of your pages I see this:
<link href="./qa-plugin/q2a-embed-master/qa-embed.css" rel="stylesheet">
<link rel="stylesheet" href="./qa-plugin/q2a-tag-list-widget-master/tag-list.css?" TYPE="text/css">
<link rel="stylesheet" href="./qa-plugin/Welcome-Widget-master/welcome-widget.css?" TYPE="text/css">
The URLs of your CSS files are relative to the current path, so basically the location changes if the URL contains something that resembles a path or subdirectory.
Take for example this URL: http://yoalfaaz.com/4966/pardesi-ke-naam
Trying to load the CSS file ./qa-plugin/q2a-embed-master/qa-embed.css on that page will load http://yoalfaaz.com/4966/qa-plugin/q2a-embed-master/qa-embed.css which results in a 404 error.
You should change your code to output absolute URLs or root-relative URLs.
Example:
Absolute URL: http://yoalfaaz.com/qa-plugin/q2a-embed-master/qa-embed.css or //yoalfaaz.com/qa-plugin/q2a-embed-master/qa-embed.css (the last one is protocol-relative URL)
Root-relative URL: /qa-plugin/q2a-embed-master/qa-embed.css (always will start at the root of the domain)
I'm attempting to server files and assets from a subdirectory of a site, like this:
Site: /go/tools/ (index.html is the root file)
With assets linked like this: /go/tools/assets/js/main.js
using nginx, my configuration looks like this:
server {
listen 80;
listen 443 ssl http2;
server_name local.tools;
index index.html;
location /go/tools {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
root /code/testing/build;
try_files $uri /$uri /index.html =404;
}
When I load the site with the url local.tools/go/tools, the index.html page loads and the html looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" href="assets/img/favicon.ico">
<link href="assets/css/vendor/bootstrap.css" rel="stylesheet" type="text/css" />
<link href="assets/css/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>...
So that part is good. The problem is that the style and javascript aren't there. When I view the network tab, I see each asset is loading the index.html content instead of its own content.
what am I missing in my configuration so if I go to: /go/tools/assets/css/styles.css that I see the actual stylesheet?
You need to use below config
location /go/tools {
location /go/tools/assets/ {
alias /code/testing/build/assets/;
}
alias /code/testing/build;
try_files $uri $uri/ /index.html =404;
}
Basically when url is /go/tools/assets you need the search to happen from /assets in the build directory. That is why we need alias in the nested location