Landing page in nginx, keep other urls - nginx

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;
}

Related

Amazon S3 rewrote uploaded PDF names with "+" in the filename as "%2B", can't access them from nginx server

I'm using S3 Uploads to offload my WordPress Media Library to an S3 bucket. I used the AWS CLI to bulk migrate my local Media Files to the S3 bucket. So far so good.
Some of the existing PDFs in my library had "+" in the filename, example "mypdf+_name.pdf". When uploaded to S3, the object name was changed to "mypdf%2B_name.pdf". According to this thread, this seems to be a long-running thing.
I tried to set up an nginx config to rewrite anything in my WordPress Media Library that has a "+" in it to go to the corrected S3 URL:
location ~ "^/wp-content/uploads/(.*)$" {
location ~ "^/wp-content/uploads/(.*)\+(.*)$" {
rewrite "^/wp-content/uploads/(.*)\+(.*)$" "https://s3-us-west-2.amazonaws.com/mybucket/uploads/$1%2B$2" redirect;
}
}
This seems to perform the requested redirect, except the "+" is not getting rewritten as "%2B".
For example, "http://example.com/wp-content/uploads/2013/10/mypdf+_name.pdf" gets redirected to "https://s3-us-west-2.amazonaws.com/mybucket/uploads/2013/10/mypdf+_name.pdf". This returns an "AccessDenied" error from S3; when I manually change the "+" to "%2B" in the URL bar, my file displays as expected.
To test if there wasn't something else wrong with my configuration, I changed the redirect to some nonsense, keeping the "%2B":
location ~ "^/wp-content/uploads/(.*)$" {
location ~ "^/wp-content/uploads/(.*)\+(.*)$" {
rewrite "^/wp-content/uploads/(.*)\+(.*)$" "https://s3-us-west-2.amazonaws.com/mybucket/uploads/$1%2B$2blahblahblah" redirect;
}
}
This results in "http://example.com/wp-content/uploads/2013/10/mypdf+_name.pdf" -> "https://s3-us-west-2.amazonaws.com/mybucket/uploads/2013/10/mypdf+_name.pdfblahblahblah"
So my redirect is "working", but something along the way is choosing to keep "+" instead of translating it to "%2B".
How can I make nginx redirect my file to the correct URL?
Here's what ended up working for me:
location ~ "^/wp-content/uploads/(.*)\+(.*)$" {
if ($request_uri ~ "^/wp-content/uploads/(.*)\+(.*)$"){
set $modified_uri "/$1%2B$2";
return 302 https://s3-us-west-2.amazonaws.com/mybucket/uploads$modified_uri;
}
}
If anyone sees an obvious problem with this let me know. I know I've read using if blocks inside a location is bad but the documentation indicates using a return directive is kosher so I'm rolling with it for now.

Correct regex expression for the location block inorder to capture CSS and JS when the request URL changes

I have developed nginx config file order to cater some custom error pages. I have created two location blocks to capture the main index.html file and other location to capture the css/js and the images. I have created the cs and the js files seperately and called into the main index file due to the ease of use. But this work only for the following types of url
https://example.com
https://example.com/abcd/
But if the url cahnges to
https://exmaple.com/abcd/efgd/ or more the css and js won't be in the response.
The css/js and images are in a directory named techops-page-resources. So after checking bit on the issue I found that on the first two url it'll get https://exmaple.com/resources as expected when the given domain is not available. But on the other occasions it'll transformed into https://example.com/abcd/resources/ and this uri doesn't exist. So I've tried different regex patterns and none of them seem to work. The following are the location blocks that I have implemented to set the error pages up.
error_page 503 /pages/maintenance.html;
error_page 502 /pages/50x.html;
error_page 404 /pages/40x.html;
location /pages/ {
root /var/www/html/ErrorPages/;
}
location /techops-page-resources {
alias /var/www/html/ErrorPages/pages/techops-page-resources/;
}
}
What I expecting is whenever the 404 error returns I want the main index file to call the techops-page-resources and include them in the the final customized 404 error page as expected. But currently what I only receive is the basic index.html file which is in the pages directory. Is there a correct regex pattern to match only the techops-page-resource as a postfix match as follows
location **some_regex_pattern**/techops-page-resources {
alias /var/www/html/ErrorPages/pages/techops-page-resources/;
}
I would love to do this in this same architecture without using inline css or js

Add child-site to path of parent site in Nginx

In the interests of keeping my codebase modular, I have two static websites - site_a, which is the parent site, and site_b, which may be considered a child site. I am trying to find the right way to append site_b to a path of site_a, such that site_a/path is equivalent to the site_b's / directory.
Note that each site instance has its own set of static resources (img, css, js), and should be referenced from the corresponding web directory on the server, and there may be some overlap in the names of some of the resources (eg. style.css) and folders (eg. /img/..).
Any pointers of help would be very much appreciated!
What you are searching is a proxy_pass (Or I think it would work in your case).
site_a configuration:
location = /path {
return 301 /path/;
}
location = /path/ {
proxy_pass http://site_b/;
}
This should work if you only want it to be exactly like this, be careful, because the /path part is changed by / , but if you need the rest of the url, you could do:
location = /path {
return 301 /path/;
}
location /path/ {
proxy_pass http://site_b/;
}
Like this, site_a/path/pathtoglory/ would show site_b/pathtoglory/.
Choose whichever you like the most (or fits your actual situation).
Any more info on proxy_pass for special configurations can be found here:
https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/

select server block based on existence of certain query parameters

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)

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