select server block based on existence of certain query parameters - nginx

I have a single page application, I want to make it crawlable so I have generated snapshots. My application stack is rails + unicorn + nginx(as reverse proxy).
Now, Aws Opsworks generates a nginx config from this cookbook. I ssh-ed into the system & modified the default config to include the following lines to redirect all requests from search engine bots as follows(they convert the url which contains #! & send a new request with _escaped_fragment_ in query parameters):
if ($args ~ "_escaped_fragment_=(.+)") {
rewrite ^ /snapshots$uri$1?;
}
Everything worked great when I loaded the url in the browser. The issue I am facing is with automating the same thing using chef. Since the code I added was in the config file generated using default cookbook by opsworks, I need a way to define a nginx server block to achieve this. So, I defined the following server block.
server {
listen 80;
server_name example.com;
if ($args ~ "_escaped_fragment_=(.+)") {
set $foo $1;
rewrite ^ /snapshots$uri$foo?;
}
}
But nginx will never select this block given there already exists another server block with the same server_name. So, is there a way that I can define a server block to be selected by nginx based on the existence of _escaped_fragment_ in the $args ?
Something as follows(I know this won't work since regex doesn't match query parameters)
server {
listen 80;
server_name example.com(.+)_escaped_fragment_=(.+);
...
}

In order to do this in chef, you need to create a custom cookbook (if you don't have one already) and a recipe in it which would overwrite the opsworks generated file with your preferred file. In the cookbook you'd need 2 files, nginx template and a recipe to overwrite the default template with the custom one:
mycookbook -> templates -> default -> custom_nginx.erb
mycookbook -> recipes -> customise_nginx.rb
Content of (1):
whatever you want your nginx config file to be, so:
server {
listen 80;
server_name example.com;
if ($args ~ "_escaped_fragment_=(.+)") {
set $foo $1;
rewrite ^ /snapshots$uri$foo?;
}
}
Content of (2):
template "/etc/nginx/sites-enabled/<nginx file name>" do
source "custom_nginx.erb"
user "root"
group "root"
mode "644"
end
service "nginx" do
action :reload
end
Then add mycookbook::customise_nginx to the custom setup recipe section in your layer settings.
If you don't have a custom cookbook already, a bit more set up will be needed:
https://www.digitalocean.com/community/tutorials/how-to-create-simple-chef-cookbooks-to-manage-infrastructure-on-ubuntu
http://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-installingcustom-enable.html
Edit:
If you want to keep opsworks config file, you have two options: to take the template that opsworks is using, I'm guessing this one? https://github.com/aws/opsworks-cookbooks/blob/release-chef-11.10/nginx/templat‌​es/default/site.erb, create a copy and put your changes there in file 1 as above. Or use chef to modify the existing file content - for example using FileEdit library (check the second answer to this question)

Related

Landing page in nginx, keep other urls

I have a Nginx + app in laravel. Right now it is working fine, but I need to show some important announcements to users - so I just create a simple index.html file.
How to setup Nginx to behave as follows:
when the user type "main URL" - example.org just display a static HTML with the temporary announcement
when the user types URL to something on the page - example.org/something - then just show him laravel app
Update # 2022.05.22
The following solution is not workable if the requested URI ends with a slash (which is exactly the case when a root request GET / HTTP/<version> is made). The reason is the index module (which is called before the static module) see that request URI ended with slash, checks it for being a directory and returns an error if it isn't. The right solution is to rewrite the URI to make it not ended with a slash, and provided below the not working one.
Not working
You can use an "exact match" location:
server {
...
location = / {
alias /full/path/to/your/stub.html;
}
# rest of the config remains as it was
location / {
...
}
location ~ \.php$ {
...
}
...
}
Using an alias directive you can specify any HTML file from any directory on your server no matter what your root directive is set to.
Working
location = / {
root /path/to/static; # needed only if the path differs from the global root
rewrite ^ /stub.html break;
}

Nginx Several projects in different directories

first of all apologies for my English, since it is not very good. I am a novice in nginx and I have a fundamental doubt:
What is the easiest way to serve several projects with nginx (separated in different directories), using a single machine, with the same ip and same port?
example.com/project1
example.com/project2
example.com/project3
A cordial greeting.
You will want several location directives inside a single server block to do what you need to do for each project. What goes inside of the location directives really depends on the type of projects they are. I have some WordPress instances, for example, that would have fastcgi config lines inside of those location directives.
Example:
server {
listen 80;
server_name example.com;
location /project1 {
# What goes here depends on what type of project this is.
}
location /project2 {
# What goes here depends on what type of project this is.
}
location /project3 {
# What goes here depends on what type of project this is.
}
}

Rewrite rule to add characters to beginning of urls in nginx where they are missing

I'm working on a legacy site where all urls must begin with the single available language code '/en'.
Is it possible with nginx to rewrite urls that do not begin with '/en' so that it is added (the legacy application will then be able to find the content and serve it)?
E.g.
http://www.example.com/ -> http://www.example.com/en/
http://www.example.com/page1 -> http://www.example.com/en/page1
http://www.example.com/en/page1 -> http://www.example.com/en/page1
Yes, this is possible. It's a bit difficult to give you a full solution since you haven't provided the config file, but I'll give it a shot.
You're looking for something along the lines of:
if ($request_uri !~ "^/en.*"){
return 301 $scheme://www.example.com/en$uri;
}
Note: This should appear immediately after your server_name and listen directives and not in a location block (see here).
I hope this helps.

The default CSS of Django admin section is not loading

Folks, the default CSS of my Django admin section is not loading (setup uses nginx reverse proxy + gunicorn, OS is the Debian-based Ubuntu).
The following is part of etc/nginx/sites-available/myproject:
location /static/admin {
alias /home/mhb11/.virtualenvs/myenv/local/lib/python2.7/site-packages/django/contrib/admin/static/;
}
That, btw, points to the correct location of django admin's css files, and is written below location /static/ {} snippet (not shown here).
Note that I have tried the root directive instead of alias too, to no avail. Also note that this error pertains solely to django admin static files. The project related static files are working perfectly. Also note that my settings.py file includes 'django.contrib.staticfiles', in INSTALLED_APPS and STATIC_URL = '/static/'.
What am I missing? Please ask for more information in case it is needed.
It may not be significant, but for consistency, your location path and alias path should both end with a / or neither end with a /.
With your current configuration, the server is constructing path names with an embedded //, like /home/mhb11/.virtualenvs/myenv/local/lib/python2.7/site-packages/django/contrib/admin/static//somefile.css.
Try:
location /static/admin/ {
alias /home/mhb11/.virtualenvs/myenv/local/lib/python2.7/site-packages/django/contrib/admin/static/;
}

How to make nginx to stop processing other rules and serve a specific location?

I have this config that works as expected in an empty server { } definition
location ^~ /foo/ {
alias /var/www/foo/;
}
But when I move this in a considerably bigger server definition (one used for a WordPress multi-site config), it will stop working and wordpress will respond to it (which obviously was not my intent).
I tried to put at the begining or end of server block, but this didn't change it.
How can I force Nginx to use this location?
You are probably looking for break.
location ^~ /foo/ {
alias /var/www/foo/;
break;
}
From the HttpRewriteModule documentation:
last - completes processing of current rewrite directives and
restarts the process (including rewriting) with a search for a match
on the URI from all available locations.
break - completes processing of current rewrite directives and
non-rewrite processing continues within the current location block
only.
Note that outside location blocks, last and break are effectively the
same.
Location blocks in Nginx are exclusive. If you use location ^~ then other rules probably expiry headers for static objects will not apply unless you copy those rules as nested under the same location block.
If you could share your full config then I can make it work for you. Most likely you need to use nested location blocks.
location = /aliasname/ {
alias /path/to/alias/
}
Trailing slash will be a problem if it is not present in URI.
See https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms#matching-location-blocks

Resources