I am running Nginx which is configured to allow me to access several resources on another server which is available as a reverse proxy. For example
main server:http://example.com
slave: http://example.com/slave
adminer on slave: http://example.com/slave/admin/adminer.php
Everything is all right so far. I enter my DB user name and password in Adminer and the trouble begins. Examining the headers returned by Adminer post-login I have noticed that it sends back this header:
Location: /admin/adminer.php?username=user
This is the root of the trouble. On my browser this, naturally, gets interpreted as meaning relative to the current server rather than the reverse proxy. I tried hacking the adminer code after locating the one place where it has a Location header but that just stopped it dead in its tracks.
How can I prevent this from happening? I have considered running a Lua script on Nginx that examines the header and replaces it but it strikes me that even if I get that to work I will be getting my server to do a great deal of unnecessary work.
Edit
After exploring the issue a bit more I am starting to think that adminer may not being doing much wrong. It actually uses the $_SERVER['REQUEST_URI'] value to construct the location header and that happens to have little part from /admin/adminer.php. I have noted that the referer, $_SERVER['HTTP_REFERRER'] has the full original request path http://example.com/slave/admin/adminer.php. So the solution would be to send back the location /slave/admin/adminer.php?username=user.
Easy? Well, the issue is that in my setup /slave/ is going to be variable so I need to resolve it in code. I can probably do that reasonably easily with a spot of PHP but I wonder... surely there is an easier alternative provided by Nginx?
I should perhaps mention:
Ubuntu 14.04 on both master & slave
Nginx 1.6.2 installed vial apt-get nginx-extras (the Lua module enabled flavor)
php5-fpm 5.5.9
MariaDB 10
Adminer 4.2.1
I had the same issue and this is how I resolved it:
upstream adminer {
server adminer;
}
server {
listen 80;
location /adminer/ {
proxy_set_header X-Forwarded-Prefix "/adminer";
proxy_pass http://adminer/;
}
}
I hit the same problem and the most simple fix I could come up with is to patch the adminer PHP script. I simply hardcoded $_SERVER["REQUEST_URI"] at the start of adminer.php like this:
--- adminer.php 2015-10-22 12:31:18.549068888 +0300
+++ adminer.php 2015-10-22 12:31:40.097069554 +0300
## -1,4 +1,5 ##
<?php
+$_SERVER["REQUEST_URI"] = "/slave/admin/adminer.php";
/** Adminer - Compact database management
* #link http://www.adminer.org/
* #author Jakub Vrana, http://www.vrana.cz/
If you put the above in a file called fix you can simply run
patch < /path/to/fix in the directory containing adminer.php you should get the correctly working version. Running patch -R < /path/to/fix will restore the original behavior if needed.
To understand the structure of a patch file read this SO thread.
Related
I am running into a file upload error with files > 10M. I have followed the advice here: http://meteor-up.com/docs.html#advanced-configuration which says how to set it in the nginx proxy by setting the clientUploadLimit: '50M'
I pushed the changes using mup proxy reconfig-shared, and it told me it had restarted the proxy. It didn't work, I still get the 413 (Request Entity Too Large) error.
I checked inside the nginx-proxy docker instance, and the file /etc/nginx/conf.d/my_proxy.conf has the correct entry client_max_body_size 50M. I restarted the EC2 box to make sure, but it's still not working.
This article https://www.tecmint.com/limit-file-upload-size-in-nginx/ suggests that the setting needs to go inside a http block, like this:
By default, Nginx has a limit of 1MB on file uploads. To set file upload size, you can use the client_max_body_size directive, which is part of Nginx’s ngx_http_core_module module. This directive can be set in the http, server or location context.
http {
client_max_body_size 100M;
}
I can't see how to achieve this, as the .conf file is read only and somehow locked.
Any ideas on how to proceed?
I suppose I could try a custom nginx.conf file, but I'm not sure what should go in there, and in fact whether it will even improve the situation.
Any help is appreciated :)
I'm happy to report that I solved it... I will explain how.
I was setting the limit in the nginx reverse proxy in the mup.js file
proxy: {
domains: 'website.com,www.website.com',
shared: { clientUploadLimit: '50M' }
}
But it turns out that there is an option to set it for each independent server like this:
proxy: {
domains: 'website.com,www.website.com',
clientUploadLimit: '50M'
}
The limit was being set to 10M by default. I found it by shelling into the nginx-proxy docker image and doing a search with the command grep -R client_max_body_size /etc/nginx and it showed me all the places where it was set (for each vhost)
So I changed the mup.js file for my server, did a mup stop, and a mup setup (to re-do the settings) and then a mup deploy
Now this is speculation but have you tried going to the docker container's root shell changed the permissions to give write permission to root or your user chmod 760 /etc/nginx/nginx.conf and edit the nginx file there?
I have GraphDb (standlone server version) in Ubuntu Server 16 running in localhost (with the command ./graphdb -d in /etc/graphdb/bin). But I only have ssh access to the server in the terminal, can't open Worbench in localhost:7200 locally.
I have many websites running on this machine with Ningx. If I try to access the machine's main IP with the port 7200 through the external web it doesn't work (e.g. http://193.133.16.72:7200/ = "connection timmed out").
I have tried to make a reverse proxy with Nginx with this code ("xxx" = domain):
listen 7200;
listen [::]:7200;
server_name sparql.xxx.com;
location / {
proxy_pass http://127.0.0.1:7200;
}
}
But all this fails. I checked and port 7200 is open in firewall (ufw). In the logs I get info that GraphDB is working locally in some testes. But I need Workbench access to import and create repositories (not sure how to do it or if it is possible without the Workbench GUI).
Is there a way to connect through the external web to the Workbench using a domain/IP and/or Nginx?
Read all the documentation and searched all day, but could not find a way to deal with this sorry. I only used GraphDB locally (the simple installer version), never used the standalone server in production before, sorry.
PS: two extra questions related:
a) For creating an URI endpoint it is the same procedure?
b) For GraphDB daemon to start automattically at boot time (with the command ./graphdb -d in graph/bin folder), what is the recommended way and configuration? (tryed the line "/etc/graphdb/bin ./graphdb -d" in rc.local but it didn't worked).
In case it is usefull for someone, I was able to make it work with this Nginx configuration:
server {
listen 80;
server_name sparql.xxxxxx.com;
location / {
proxy_pass http://localhost:7200;
proxy_set_header Host $host;
}
}
I think it was the "proxy_set_header Host $host;" that solved it (tried the rest without it before and didn't worked). I think GraphDB uses some headers to set configurations, and they were not passing.
I wounder if I am forgetting something else important to forward in the proxy, but in this moment the Worbench seams to work and opens in the domain used "sparql.xxxxxx.com".
I'm using vagrant (VVV actually) to run local wordpress installs. I want to test different behaviors for different GEO's on my local machine instead of upload it every time to the server which is annoying.
So, I've tried to install the GeoIP nginx module to the local machine with the following guide https://piwik.org/faq/how-to/faq_166/ (and a bit more google but it doesn't matter at the moment).
When I'm using ./configure the following is exists:
checking for GeoIP library ... found
checking for GeoIP IPv6 support ... found
I've also set the .dat files in my conf file, and set the $_SERVER (fastcgi_param) parameters - so they displayed when I'm printing the $_SERVER var.
But those GeoIP vars are empty. I'm not sure about the reason, but 2 things is bothering me. First, when I'm write nginx -V in the terminal the argument --with-http_geoip_module is missing. Second, could it actually works if the REMOTE_ADDR (IP) is not my real IP? (192.168.1.50 for example).
nginx is a bit strange for me, so sorry if something isn't exact..
--
Operating system - macOS, nginx version - 1.3.15, running with VVV (vagrant box)
If there is a reverse proxy in front of your nginx, use geoip_proxy to set IPs whose X-Forwarded-For-Header can be trusted.
You can also use that without actually having a reverse proxy when you're developing. Add your local IP to the geoip_proxy-list and set the X-Forwarded-For-Header to your public IP in your browser (use a plugin like Modify Headers).
I use nginx along with fastcgi. I see a lot of the following errors in the error logs
readv() failed (104: Connection reset
by peer) while reading upstream and
recv() failed (104: Connection reset
by peer) while reading response header
from upstream
I don't see any problem using the application. Are these errors serious or how to get rid of them.
I was using php-fpm in the background and slow scripts were getting killed after a said timeout because it was configured that way. Thus, scripts taking longer than a specified time would get killed and nginx would report a recv or readv error as the connection is closed from the php-fpm engine/process.
Update:
Since nginx version 1.15.3 you can fix this by setting the keepalive_requests option of your upstream to the same number as your php-fpm's pm.max_requests:
upstream name {
...
keepalive_requests number;
...
}
Original answer:
If you are using nginx to connect to php-fpm, one possible cause can also be having nginx' fastcgi_keep_conn parameter set to on (especially if you have a low pm.max_requests setting in php-fpm):
http|server|location {
...
fastcgi_keep_conn on;
...
}
This may cause the described error every time a child process of php-fpm restarts (due to pm.max_requests being reached) while nginx is still connected to it. To test this, set pm.max_requests to a really low number (like 1) and see if you get even more of the above errors.
The fix is quite simple - just deactivate fastcgi_keep_conn:
fastcgi_keep_conn off;
Or remove the parameter completely (since the default value is off). This does mean your nginx will reconnect to php-fpm on every request, but the performance impact is negligible if you have both nginx and php-fpm on the same machine and connect via unix socket.
Regarding this error:
readv() failed (104: Connection reset by peer) while reading upstream and recv() failed (104: Connection reset by peer) while reading response header from upstream
there was 1 more case where I could still see this.
Quick set up overview:
CentOS 5.5
PHP with PHP-FPM 5.3.8 (compiled from scratch with some 3rd party
modules)
Nginx 1.0.5
After looking at the PHP-FPM error logs as well and enabling catch_workers_output = yes in the php-fpm pool config, I found the root cause in this case was actually the amfext module (PHP module for Flash).
There's a known bug and fix for this module that can be corrected by altering the amf.c file.
After fixing this PHP extension issue, the error above was no longer an issue.
This is a very vague error as it can mean a few things. The key is to look at all possible logs and figure it out.
In my case, which is probably somewhat unique, I had a working nginx + php / fastcgi config. I wanted to compile a new updated version of PHP with PHP-FPM and I did so. The reason was that I was working on a live server that couldn't afford downtime. So I had to upgrade and move to PHP-FPM as seamlessly as possible.
Therefore I had 2 instances of PHP.
1 directly talking with fastcgi (PHP 5.3.4) - using TCP / 127.0.0.1:9000 (PHP 5.3.4)
1 configured with PHP-FPM - using Unix socket - unix:/dir/to/socket-fpm
(PHP 5.3.8)
Once I started up PHP-FPM (PHP 5.3.8) on an nginx vhost using a socket connection instead of TCP I started getting this upstream error on any fastcgi page taking longer than x minutes whether they were using FPM or not. Typically it was pages doing large SELECTS in mysql that took ~2 min to load. Bad I know, but this is because of back end DB design.
What I did to fix it was add this in my vhost configuration:
fastcgi_read_timeout 5m;
Now this can be added in the nginx global fastcgi settings as well. It depends on your set up. http://wiki.nginx.org/HttpFcgiModule
Answer # 2.
Interestingly enough fastcgi_read_timeout 5m; fixed one vhost for me.
However I was still getting the error in another vhost, just by running phpinfo();
What fixed this for me was by copying over a default production php.ini file and adding the config I needed into it.
What I had was an old copy of my php.ini from the previous PHP install.
Once I put the default php.ini from 'shared' and just added in the extensions and config I needed, this solved my problem and no longer did I have nginx errors readv() and recv() failed.
I hope 1 of these 2 fixes helps someone.
Also it can be a very simple problem - there is an infinity cicle somewhere in your code, or an infinity trying to connect an external host on your page.
Some times this problem happen because of huge of requests. By default the pm.max_requests in php5-fpm maybe is 100 or below.
To solve it increase its value depend on the your site's requests, For example 500.
And after the you have to restart the service
sudo service php5-fpm restart
Others have mentioned the fastcgi_read_timeout parameter, which is located in the nginx.conf file:
http {
...
fastcgi_read_timeout 600s;
...
}
In addition to that, I also had to change the setting request_terminate_timeout in the file: /etc/php5/fpm/pool.d/www.conf
request_terminate_timeout = 0
Source of information (there are also a few other recommendations for changing php.ini parameters, which may be relevant in some cases): https://ma.ttias.be/nginx-and-php-fpm-upstream-timed-out-failed-110-connection-timed-out-or-reset-by-peer-while-reading/
There's an option to hide the version so it will display only nginx, but is there a way to hide that too so it will not show anything or change the header?
If you are using nginx to proxy a back-end application and want the back-end to advertise its own Server: header without nginx overwriting it, then you can go inside of your server {…} stanza and set:
proxy_pass_header Server;
That will convince nginx to leave that header alone and not rewrite the value set by the back-end.
The last update was a while ago, so here is what worked for me on Ubuntu:
sudo apt-get update
sudo apt-get install nginx-extras
Then add the following two lines to the http section of nginx.conf, which is usually located at /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
server_tokens off; # removed pound sign
more_set_headers 'Server: Eff_You_Script_Kiddies!';
Also, don't forget to restart nginx with sudo service nginx restart.
Like Apache, this is a quick edit to the source and recompile. From Calomel.org:
The Server: string is the header which
is sent back to the client to tell
them what type of http server you are
running and possibly what version.
This string is used by places like
Alexia and Netcraft to collect
statistics about how many and of what
type of web server are live on the
Internet. To support the author and
statistics for Nginx we recommend
keeping this string as is. But, for
security you may not want people to
know what you are running and you can
change this in the source code. Edit
the source file
src/http/ngx_http_header_filter_module.c
at look at lines 48 and 49. You can
change the String to anything you
want.
## vi src/http/ngx_http_header_filter_module.c (lines 48 and 49)
static char ngx_http_server_string[] = "Server: MyDomain.com" CRLF;
static char ngx_http_server_full_string[] = "Server: MyDomain.com" CRLF;
March 2011 edit: Props to Flavius below for pointing out a new option, replacing Nginx's standard HttpHeadersModule with the forked HttpHeadersMoreModule. Recompiling the standard module is still the quick fix, and makes sense if you want to use the standard module and won't be changing the server string often. But if you want more than that, the HttpHeadersMoreModule is a strong project and lets you do all sorts of runtime black magic with your HTTP headers.
It’s very simple: Add these lines to server section:
server_tokens off;
more_set_headers 'Server: My Very Own Server';
Simple, edit /etc/nginx/nginx.conf and remove comment from
#server_tokens off;
Search for http section.
Install Nginx Extras
sudo apt-get update
sudo apt-get install nginx-extras
Server details can be removed from response by adding following two lines in the nginx.conf (under http section)
more_clear_headers Server;
server_tokens off;
There is a special module: http://wiki.nginx.org/NginxHttpHeadersMoreModule
This module allows you to add, set, or clear any output or input header that you specify.
This is an enhanced version of the standard headers module because it provides more utilities like resetting or clearing "builtin headers" like Content-Type, Content-Length, and Server.
It also allows you to specify an optional HTTP status code criteria using the -s option and an optional content type criteria using the -t option while modifying the output headers with the more_set_headers and more_clear_headers directives...
If you're okay with just changing the header to another string five letters or fewer, you can simply patch the binary.
sed -i 's/nginx\r/thing\r/' `which nginx`
Which, as a solution, has a few notable advantages. Namely, that you can allow your nginx versioning to be handled by the package manager (so, no compiling from source) even if nginx-extras isn't available for your distro, and you don't need to worry about any of the additional code of something like nginx-extras being vulnerable.
Of course, you'll also want to set the option server_tokens off, to hide the version number, or patch that format string as well.
I say "five letters or fewer" because of course you can always replace:
nginx\r\0
with
bob\r\0\r\0
leaving the last two bytes unchanged.
If you actually want more than five characters, you'll want to leave server_tokens on, and replace the (slightly longer) format string, although again there's an upper limit on that length imposed by the length of the format string - 1 (for the carriage return).
...If none of the above makes sense to you, or you've never patched a binary before, you may want to stay away from this approach, though.
According to nginx documentation it supports custom values or even the exclusion:
Syntax: server_tokens on | off | build | string;
but sadly only with a commercial subscription:
Additionally, as part of our commercial subscription, starting from
version 1.9.13 the signature on error pages and the “Server” response
header field value can be set explicitly using the string with
variables. An empty string disables the emission of the “Server”
field.
After I read Parthian Shot's answer, I dig into /usr/sbin/nginx binary file. Then I found out that the file contains these three lines.
Server: nginx/1.12.2
Server: nginx/1.12.2
Server: nginx
Basically first two of them are meant for server_tokens on; directive (Server version included).
Then I change the search criteria to match those lines within the binary file.
sed -i 's/Server: nginx/Server: thing/' `which nginx`
After I dig farther I found out that the error message produced by nginx is also included in this file.
<hr><center>nginx</center>
There are three of them, one without the version, two of them included the version. So I run the following command to replace nginx string within the error message.
sed -i 's/center>nginx/center>thing/' `which nginx`
The only way is to modify the file src/http/ngx_http_header_filter_module.c . I changed nginx on line 48 to a different string.
What you can do in the nginx config file is to set server_tokens to off. This will prevent nginx from printing the version number.
To check things out, try curl -I http://vurbu.com/ | grep Server
It should return
Server: Hai
I know the post is kinda old, but I have found a solution easy that works on Debian based distribution without compiling nginx from source.
First install nginx-extras package
sudo apt install nginx-extras
Then load the nginx http headers more module by editing nginx.conf and adding the following line inside the server block
load_module modules/ngx_http_headers_more_filter_module.so;
Once it's done you'll have access to both more_set_headers and more_clear_headers directives.
Expanding on Parthian Shot's answer, you can actually replace the whole header and not only the value as long as the total length is the same:
sed -i 's/Server: nginx/My-Header: hi/' `which nginx`
Nginx-extra package is deprecated now.
The following therefore did now work for me as i tried installing various packages
more_set_headers 'Server: My Very Own Server';
You can just do the following and no server or version information will be sent back
server_tokens '';
if you just want to remove the version number this works
server_tokens off;
Are you asking about the Server header value in the response? You can try changing that with an add_header directive, but I'm not sure if it'll work. http://wiki.codemongers.com/NginxHttpHeadersModule