I'm trying to do something which seems fairly trivial to me, but can't seem to get it right with Caddy.
I have the following site configured with Caddy:
foo.com {
tls {
dns cloudflare ...
}
reverse_proxy /* http://proxy-foo
}
I'm now trying to enable a maintenance page, such that all requests serve the maintenance html, and return a 503 status code. But, I can either serve the page, or the status code, but not both.
I first tried the handle_errors directive, with a respond directive
foo.com {
tls {
dns cloudflare ...
}
# reverse_proxy /* http://proxy-foo
handle_errors {
rewrite * /503.html
file_server
}
respond * 503
}
only to later read the caveat that respond doesn't trigger the error handlers.
Also tried removing all other directives, thinking that would trigger a 404, which would in turn call the handle_errors block, but that too doesn't work. It just ends up returning 200, but with no body.
Any pointers as to where I'm going wrong much appreciated.
You can try configure reverse_proxy directive.
That code similar to docs example is worked for me:
:80
reverse_proxy localhost:8000 {
#error status 500 503
handle_response #error {
respond "Something bad happened. If the error occurs again, please contact me at example#mail.com"
# i guess we can use other directives like redirect
}
}
Related
Assume my web app is hosted on https://example.com, I am testing my HTTP verbs on my server, I have nginx there,
curl -v -X TRACE https://example.com
For above I am getting a response. Instead, I should get 404 or other.
I had tried the below conf in Nginx server location block.
if ($request_method !~ ^(GET|HEAD|POST)$ ){
return 444;
}
This works for me but TRACE is still allowed. How should I stop it?
You could try using limit_except instead, like this:
location / {
limit_except GET HEAD POST { deny all; }
}
Consider the following nginx config file:
server {
listen 443;
ssl on;
ssl_certificate /etc/tls/cert.pem;
ssl_certificate_key /etc/tls/key.pem;
location / {
proxy_pass http://api.default.svc.cluster.local;
}
}
All incoming TCP requests on 443 should redirect to my server running on api.default.svc.cluster.local:80 (which is a node REST-Api btw). This works fine, I can curl https://<nginx-IP>/ nginx and get a correct response, as expected.
Now, I'd like to change the location from / to /api, so I can fire a curl https://<nginx-IP>/api in order to get the same response as before.
1. Attempt
So I change the location line in the config to:
location /api {
Unfortunately this won't work, instead I get an error Cannot GET /api which is a node error, so obviously it gets routed to the api but something's still smelly.
2. Attempt
It seems as the trailing slash in an URI is required so I added it to the location:
location /api/ {
Now something changed. I won't get the same error as before, instead I get an "301 moved permanently". How can I fix my nginx config file?
Additional information regarding the environment
I'm using a kubernetes deployment that deploys the nginx reverse proxy incl. the config introduced. I then expose nginx using a kubernetes service. Also, I tried using kubernetes ingress to deal with this situation, using the same routes, however, the ingress service would respond with a default backend - 404 message.
As mentioned in the question, trailing slashes in URIs are important. I fixed this in the location, however, I didn't add it to the URI I pass using proxy_pass.
As for the nginx proxy I got it to work using the following config:
server {
listen 443;
ssl on;
ssl_certificate /etc/tls/cert.pem;
ssl_certificate_key /etc/tls/key.pem;
location /api/ {
proxy_pass http://api.default.svc.cluster.local/;
}
}
Concerning the ingress solution, I was not able to get it to work by adding the missing trailing slash to the path. The service is specified due its name and therefore no trailing slash can be added (i.e. it would result in an error).
I'm writing a web application using MEAN Stack and I've encountered a problem that I cannot solve, no matter what I try or search.
I'm trying to login using passport/passport-facebook with ExpressJS. If I write in the URL of my browser localhost/api/auth/facebook everything runs fine.
However if I create an element in my HTML code like this Login with Facebook it takes me to my 404 page (see nginx below).
And if I try with the Angular way, like this <button ng-click="login_fb()">Login with Facebook</button>, I get a No 'Access-Control-Allow-Origin' header is present on the requested resource. error.
I believe that I should use the <a href="..."> element but I think my nginx script is blocking it, since I enabled CORS on my NodeJS Server, with this:
server.all('/*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
next();
});
I'll leave my nginx script too (ignore the blocks inside '<' and '>'):
worker_processes 4;
events {
worker_connections 1024;
}
http {
upstream backend {
server 127.0.0.1:8080;
}
# To optimize the response of static files
sendfile on;
server {
# Listen to normal port
listen 80;
# Let through files like CSS, JPG, JS, ...
include mime.types;
# Alias for this server
server_name <my-domain>;
# Where the HTML files are located
root <my-folder>;
# Route for API calls
location /api/ {
proxy_pass http://backend;
}
# Route for the index
location ~ ^/*$ {
index index.html index.htm;
}
# Route for 404 page
error_page 404 /index.html;
}
}
EDIT: Using the link like this Login with Facebook but it forces me to use the URL hardcoded and I'll eventually put this app under a domain.
NEW EDIT: I realise that using like this Login with Facebook doesn't work because it thinks it a Angular route, and since I haven't declared in $routeProvider, it takes me to 404.
To avoid the 404, add target="_self" to your link Login with Facebook. It will bypass the angular router.
With the other method, I think you get No 'Access-Control-Allow-Origin' because when you use the angular $http service it's blocked by CORS same-origin policy at the FB API.
You should stick to the link, if you want to do this on the angular end, I recommend this plugin: https://github.com/sahat/satellizer.
I've been having a bit of difficulty setting up nginx on my ubuntu server. Right now its configured to proxy another website. I want to add some content to the main page right after <body>. I used:
subs_filter '<body>' '<body>' My content;
This works great, the only problem is that it's at every page, How can I use an if statement or something to make it only appear on the homepage. I tried going with
if ($uri ~ 'index.php') then do the above filter but that gives an error saying nginx: [emerg] "subs_filter" directive is not allowed here.
I looked it up but had a lot of trouble finding what I need :(.
According to nginx documentation subs_filter may in used in the http, server and location contexts.
Thus, in order to have the filter activated only for the index.php page,
location = /index.php {
subs_filter '<body>' '<body>' My content;
# other things you would do for index.php
}
I'm having some trouble with redirects within wordpress redirection causing the domain to change.
Example:
Site - noncdn.somedomain.com
CDN URL - www.domain.com
When I open links w/o a trailing slash there is a 301 redirect:
Going here: www.domain.com/page
Takes you here: noncdn.somedomain.com/page/
Since Cloudfront is hitting the server using Origin Domain, the server doesn't even know that requests are coming in from a different domain.
How do I force this 301 to use FQDN w/ correct CDN domain instead of doing a relative redirect?
I've already added this so that links on the site and images all load from Cloudfront domain, but it seems to have no effect on the redirect behavior:
add_filter('home_url','home_url_cdn',10,2);
function home_url_cdn( $path = '', $scheme = null ) {
return get_home_url_cdn( null, $path, $scheme );
}
function get_home_url_cdn( $blog_id = null, $path = '', $scheme = null ) {
$cdn_url = get_option('home');
if(get_option('bapi_site_cdn_domain')){
$cdn_url = get_option('bapi_site_cdn_domain');
}
$home_url = str_replace(get_option('home'),$cdn_url,$path);
//echo $home_url;
return $home_url;
}
Any Help is much appreciated!
Thanks!
I was tracking down a very similar issue for a while with a Cloudfront distribution of a standard static website running on Nginx. The symptoms were the same, links with a trailing slash (e.g. www.acme.com/products/) worked correctly, but omitting the trailing slash caused the user to be redirected to the origin.
The issue is that the webserver software itself is not properly attempting to resolve URIs and is instead responding with a redirect to a URL it can serve. You can test this by using curl against your site:
$ curl http://myhost.com/noslashurl
HTTP/1.1 301 Moved Permanently [...]
CloudFront is returning exactly what your server returns, in this case a 301 redirect to your origin URL. Instead of following the redirect and caching that, CloudFront caches the redirect itself. The only way to correct this is to ensure that your origin properly handles the requests and does not respond with a 301.
In my particular case, that meant updating the try_files directive for my location in the nginx configuration. As I mentioned this is a static site, and so my try_files became:
location / {
[...]
try_files $uri $uri/index.shtml /index.shtml =404;
}
You want to be sure that the try_files has an endgame, to avoid redirection cycling which will cause your server to return 500 Server Errors when a non-existent URL is requested. In this case, /index.shtml is the last-ditch attempt and failing that, it will return a 404.
I know this doesn't precisely answer your question, but yours was one of a very few I found when searching for "cloudfront without trailing slash redirects to origin", and you've not had an answer for a year, so I figured it was worth sending a response.
I had the same problem.
I fixed the issue changing some wordpress parameters.
In the elasticbeanstalk I set the parameter CUSTOM_URL for my custom domain and in the file /var/www/html/wp-includes/load.php
I set the parameters HTTP_HOST and SERVER_NAME to same value of CUSTOM_URL, and it resolved the redirect to elasticbeanstalk url.
$_SERVER['HTTP_HOST'] = $_SERVER['CUSTOM_URL'];
$_SERVER['SERVER_NAME'] = $_SERVER['CUSTOM_URL'];