nginx: try to serve minified files first - optimization

I'm trying to optimize my websites by minifying the css, js, svg and whatnot.
This however meddles with my codebase and I would like to keep the original files around. I've set up git to autmoatically minify any css|js|svg to min.css|min.js|min.svg but I'm not editing every php or html file that links to these files to use the .min. extension.
To mend this, I was thinking that I could set up nginx serve the minified versions of the files automatically when a request for the non-minified files is done using the try_files directives and use the non-minified files as a backup if they don't exist.
This is some pseudo-configuration to elaborate what I mean:
location \.(css|js|svg) {
try_files $minified_uri $uri;
}
but I have no clue on how to get the $minified_uri here (e.g. /some/style.min.css is served when /some/style.css is requested).
Also, if you think this approach is really bad, please be free to tell me why and show me some alternatives!

This is fairly easy to accomplish using regex variables:
location ~ ^(.+)\.(css|js|svg)$ {
try_files $1.min.$2 $uri =404;
}

I don't guarantee that it would work but I guess you can give it a try
location ~ (?<name>[^/]*)\.(?<extention>css|js|svg) {
try_files $name.min.$extention $name.$extention;
}

Related

Avoid Nginx to add '/' before query parameters

I'm currently developing a Nuxt SPA that will be served with Nginx.
When I run de nuxt server localy, everything is working fine. But when runing the app on nginx, I have an issue when adding query parameters.
Actually nginx automatically rewrite all URL to add a trailing /. Thus, when add query parameter I am automatically redirected to: www.exemple.com/my-path/?my-query-param=1234.
But what I want is to access www.exemple.com/my-path?my-query-param=1234 without the /?.
I tried adding rewrite ^/(.*)/$ /$1; to my nginx conf, unfortunately, this make me fall in a redirection loop (? -> /? -> ? -> /? -> ...).
my current nginx conf is very basic:
server {
listen 80;
index index.html;
include /etc/nginx/mime.types;
}
Can someone help me to fix my issue ?
Thanks in advance.
UPDATE:
I also tried try_files $uri $uri/index.html =404; without any success :-(

nginx different authentication for different directories

finding alternative of htaccess in apache for nginx, want to add different authentication rules for different directories. Different .htpasswd files for different directories. how to do it? Just like bitbucket does, it runs on nginx too.
I'm pretty sure that the authentication within BitBucket is handled by the application, there's no .htpasswd files anywhere to be found, authentication isn't handled by the web server.
However you can configure nginx to use a different .htpasswd for different paths using different location blocks for each path
location / {
root /var/www/app/;
index index.html index.php;
auth_basic_user_file /var/www/app/.htpasswd;
}
location /pathA {
root /var/www/app/pathA;
index index.html index.php;
auth_basic_user_file /var/www/app/pathA/.htpasswd;
}
or something to that effect

nginx URL-rewrite dynamic for all subfolders

I am facing the following problem when migrating from apache to nginx:
When deploying a folder named "apps" including about 10 subfolders with zend framework 2 apps, I am not able to browse my zf-routes (http 404).
This happens because my htaccess is not read and my rewrite does not take place.
It would work when defining all projects in my nginx config but this is not very dynamic and all new projects would need a new entry while apache read the .htaccess in all folders and did it on itself.
Is there any nginx directive I did not find to accomplish this?
I am currently trying this codeblock:
location /apps/ {
try_files $uri $uri/ /index.php;
}
I know this would cause nginx to check /apps/index.php instead of /apps/(projectname)/index.php - but I don't know how to change this.
location /apps/(.*)/ {
try_files $uri $uri/ /apps/(.*)/index.php?$args;
}
This is the solution. I just missed the part before index.php.

Nginx multiple locations with rails static assets

I am new to setting up my own server with nginx so forgive any ignorance. I may have just been using the wrong search terms to find the answers to my questions.
Anyway, I am using Rails 3, Nginx, and Unicorn at the moment on a VPS on rackspace. In my rails app I have about 500mb of files in public/ and I would like to use Nginx to serve these. Typically this is just:
server {
listen 80 default deferred;
# server_name example.com;
root /home/<my_user>/apps/<my_app>/current/public;
...
}
I can make this work if I add the 500mb in public to the git repo and then deploy with capistrano, but I don't want all of those files in my git repo. It makes no sense to store them there, but if I remove them then I have to manually go upload them to my public folder on the server every time I deploy.
Is there a way to make Nginx point to a second folder of assets for it to server? I tried the following:
location /static {
gzip on;
alias /home/deployer/static/;
}
I haven't had any luck getting this to work (trying to access the files via url.com/static/...) Anyone know what I am doing wrong?
Side note: all of the shown code is in my config/nginx.conf file and it SHOULD be overriding the settings via this line in my deploy.rb:
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
location /static/ {
root /home/deployer;
}
http://nginx.org/r/alias
http://nginx.org/r/root

How to setup mass dynamic virtual hosts in nginx?

Been playing with nginx for about an hour trying to setup mass dynamic virtual hosts.
If you ever done it in apache you know what I mean.
Goal is to have dynamic subdomains for few people in the office (more than 50)
Perhaps doing this will get you where you want to be:
server {
root /sites/$http_host;
server_name $http_host;
...
}
I like this as I can literally create sites on the fly, just create new directory named after the domain and point the DNS to the server ip.
You will need some scripting knowledge to put this together. I would use PHP, but if you are good in bash scripting use that. I would do it like this:
First create some folder (/usr/local/etc/nginx/domain.com/).
In main nginx.conf add command : include /usr/local/etc/nginx/domain.com/*.conf;
Every file in this folder should be different vhost names subdomain.conf.
You do not need to restart nginx server for config to take action, you only need to reload it : /usr/local/etc/rc.d/nginx reload
OR you can make only one conf file, where all vhosts should be set. This is probably better so that nginx doesn't need to load up 50 files, but only one....
IF you have problems with scripting, then ask question about that...
Based on user2001260's answer, later edited by partlov, here's my outcome.
Bear in mind this is for a dev server located on a local virtual machine, where the .dev prefix is used at the end of each domain. If you want to remove it, or use something else, the \.dev part in the server_name directive could be edited or altogether removed.
server {
listen 80 default_server;
listen [::]:80 default_server;
# Match any server name with the format [subdomain.[.subdomain...]].domain.tld.dev
server_name ~^(?<subdomain>([\w-]+\.)*)?(?<domain>[\w-]+\.[\w-]+)\.dev$;
# Map by default to (projects_root_path)/(domain.tld)/www;
set $rootdir "/var/www/$domain/www";
# Check if a (projects_root_path)/(subdomain.)(domain.tld)/www directory exists
if (-f "/var/www/$subdomain.$domain/www"){
# in which case, set that directory as the root
set $rootdir "/var/www/$subdomain.$domain/www";
}
root $rootdir;
index index.php index.html index.htm index.nginx-debian.html;
# Front-controller pattern as recommended by the nginx docs
location / {
try_files $uri $uri/ /index.php;
}
# Standard php-fpm based on the default config below this point
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
The regex in server_name captures the variables subdomain and domain. The subdomain part is optional and can be empty. I have set it so that by default, if you have a subdomain, say admin.mysite.com the root is set to the same root as mysite.com. This way, the same front-controller (in my case index.php) can route based on the subdomain. But if you want to keep an altogether different application in a subdomain, you can have a admin.mysite.com dir and it will use that directory for calls to admin.mysite.com.
Careful: The use of if is discouraged in the current nginx version, since it adds extra processing overhead for each request, but it should be fine for use in a dev environment, which is what this configuration is good for. In a production environment, I would recommend not using a mass virtual host configuration and configuring each site separately, for more control and better security.
server_name ~^(?<vhost>[^.]*)\.domain\.com$;
set $rootdir "/var/www/whatever/$vhost";
root $rootdir;
As #Samuurai suggested here is a short version Angular 5 with nginx build integration:
server {
server_name ~^(?<branch>.*)\.staging\.yourdomain\.com$;
access_log /var/log/nginx/branch-access.log;
error_log /var/log/nginx/branch-error.log;
index index.html;
try_files $uri$args $uri$args/ $uri $uri/ /index.html =404;
root /usr/share/nginx/html/www/theft/$branch/dist;
}
Another alternative is to have includes a few levels deep so that directories can be categorized as you see fit. For example:
include sites-enabled/*.conf;
include sites-enabled/*/*.conf;
include sites-enabled/*/*/*.conf;
include sites-enabled/*/*/*/*.conf;
As long as you are comfortable with scripting, it is not very hard to put together some scripts that will quickly set up vhosts in nginx. This slicehost article goes through setting up a couple of vhosts and does it in a way that is easily scriptable and keeps the configurations separate. The only downside is having to restart the server, but that's to be expected with config changes.
Update: If you don't want to do any of the config maintaining yourself, then your only 2 options (the safe ones anyways) would be to either find a program that will let your users manage their own chunk of their nginx config (which will let them create all the subdomains they want), or to create such a user-facing management console yourself.
Doing this yourself would not be too hard, especially if you already have the scripts to do the work of setting things up. The web-based interface can call out to the scripts to do the actual work so that all the web interface has to deal with is managing who has access to what things.