Nginx upstream failure configuration file - nginx

I'm trying to start up my node service on my nginx webserver but I keep getting this error when I try to do nginx -t
nginx: [emerg] "upstream" directive is not allowed here in /etc/nginx/nginx.conf:3
nginx: configuration file /etc/nginx/nginx.conf test failed
My current nginx.conf is like this:
upstream backend {
server 127.0.0.1:5555;
}
map $sent_http_content_type $charset {
~^text/ utf-8;
}
server {
listen 80;
listen [::]:80;
server_name mywebsite.com;
server_tokens off;
client_max_body_size 100M; # Change this to the max file size you want to allow
charset $charset;
charset_types *;
# Uncomment if you are running behind CloudFlare.
# This requires NGINX compiled from source with:
# --with-http_realip_module
#include /path/to/real-ip-from-cf;
location / {
add_header Access-Control-Allow-Origin *;
root /path/to/your/uploads/folder;
try_files $uri #proxy;
}
location #proxy {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://backend;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
I tried to look up some solutions but nothing seem to work for my situation.
Edit: Yes, I did edit the paths and placeholders properly.

tldr; The upstream directive must be embedded inside an http block.
nginx configuration files usually have events and http blocks at the top-most level, and then server, upstream, and other directives nested inside http. Something like this:
events {
worker_connections 768;
}
http {
upstream foo {
server localhost:8000;
}
server {
listen 80;
...
}
}
Sometimes, instead of nesting the server block explicitly, the configuration is spread across multiple files and the include directive is used to "merge" them all together:
http {
include /etc/nginx/sites-enabled/*;
}
Your config doesn't show us an enclosing http block, so you are most likely running nginx -t against a partial config. You should either a) add those enclosing blocks to your config, or b) rename this file and issue an include for it within your main nginx.conf to pull everything together.

Related

Logging issue with Nginx reverse proxy

I am using the following Nginx reverse proxy configuration.
server {
listen 80;
listen [::]:80;
server_name www.test.com;
access_log /var/log/nginx/www.test.com.access.log;
error_log /var/log/nginx/www.test.com.error.log warn;
location / {
proxy_pass http://12.23.45.78:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
}
By adding the access_log and error_log parameters, it will log the access log.
Now I want to skip some logging, such as not logging favicon.ico and apple-touch-icon.png, so I added the following configuration.
location ~* ^/(?:favicon|apple-touch-icon) {
log_not_found off;
access_log off;
}
But here is the problem, when I do this, http://www.test.com/favicon.ico will not be accessed properly, it prompts "404 Not Found" error.
It seems to indicate that the reverse proxy host is taking over the favicon.ico access without forwarding it to upstream for processing, is this normal Nginx behavior please?
If this is normal behavior, how should I set not to log for a given resource?
Any help is appreciated in advance!
Every request ends up in some location (if not being finished before). Every location uses its own content handler. Unless you specify something explicitly via content handler declaration directive (examples include, bit not limited to proxy_pass, fastcgi_pass, uwsgi_pass, etc.), it will be a static content handler to serve the requested content from local filesystem. Check my ServerFault answers (1, 2) to find out some more details.
In some cases such a task can be solved using the map block, e.g.
map $uri $log {
~^/(?:favicon|apple-touch-icon) off;
default /var/log/nginx/access.log;
}
server {
...
access_log $log;
This approach can work when you need to implement lets say conditional basic auth (example). Unfortunately it won't work with the access_log directive - instead nginx will create the second log file named off for icon requests. So if you want every request to be passed to the 12.23.45.78 upstream, I don't see any other way but to duplicate content handler declaration for both locations. However every other used directive can be moved one level up, thus being inherited by both locations:
server {
listen 80;
listen [::]:80;
server_name www.test.com;
error_log /var/log/nginx/www.test.com.error.log warn;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
location / {
access_log /var/log/nginx/www.test.com.access.log;
proxy_pass http://12.23.45.78:8080;
}
location ~ ^/(?:fav|apple-touch-)icon {
access_log off;
proxy_pass http://12.23.45.78:8080;
}
}
On the other hand, nothing can stop you from serving those two files locally and not passing those requests anywhere. Just put them into some dedicated directory and use a location with a static content handler:
location ~ ^/(?:fav|apple-touch-)icon {
access_log off;
root /full/path/to/folder/with/icons;
}

Nginx returns HTTP Status 200 instead 302 on a proxy_pass configuration

I have the following configuration on a NGINX which is serving as a reverse proxy to my Docker machine located at: 192.168.99.100:3150.
Basically, I need to hit: http://localhost:8150 and the content displayed has to be the content from inside the Docker.
The configuration bellow is doing his job.
The point here is that when hitting the localhost:8150 I'm getting http status code 302, and I would like to get the http status code 200.
Does anyone know if it's possible to be done on Nginx or any other way to do that?
server {
listen 8150;
location / {
proxy_pass http://192.168.99.100:3150;
}
}
Response from a request to http://localhost:8150/products
HTTP Requests
-------------
GET /projects 302 Found
I have found the solution.
Looks that a simple proxy_pass doens't work quite fine with ngrok.
I'm using proxy_pass with upstream and it's working fine.
Bellow my configuration.
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream rorweb {
server 192.168.99.100:3150 fail_timeout=0;
}
server {
listen 8150;
server_name git.example.com;
server_tokens off;
root /dev/null;
client_max_body_size 20m;
location / {
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://rorweb;
}
}
include servers/*;
}
My environment is like this:
Docker (running a rails project on port 3150)
Nginx (as a reverse proxy exposing the port 8150)
Ngrok (exporting my localhost/nginx)

Tornado app in multiple nginx locations

I have 2 tornado applications and I am trying to use nginx as a proxy for them, but I need those applications to be served in the same address but different locations (Access app1 with URL http://myserver/app1, and app2 with URL http://myserver/app2).
My nginx configuration file /etc/nginx/conf.d/myserver.conf:
upstream app1 {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
upstream app2 {
server 127.0.0.1:9081;
server 127.0.0.1:9082;
}
server {
listen 80;
access_log /var/log/nginx/myserver.access.log;
error_log /var/log/nginx/myserver.error.log;
location app1/static {
root /path/to/app1/;
if ($query_string) {
expires max;
}
}
location app2/static {
root /path/to/app2/;
if ($query_string) {
expires max;
}
}
location /app1/ {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://app1/;
}
location /app2/ {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://app2/;
}
}
When I access, for instance, app1 via tornado it works fine:
Via tornado: http://myserver:8081/ redirects to login http://myserver:8081/auth/login. Good.
Via nginx: http://myserver/app1 redirects to http://myserver/auth/login (it should redirect to http://myserver/app1/auth/login).
What is the correct nginx configuration to make it work?
This is controlled by the proxy_redirects setting. You've turned it off, so when the tornado server redirects to /auth/login that gets passed through as-is. You need to either make the tornado server aware of its urls as seen by the outside world (i.e. include /app1/ in all the routes and redirects even internally) or turn on proxy_redirects to have nginx remap them. I recommend the former, since proxy_redirects only works for redirects and you'll usually run into similar issues in other places (urls for static content, for submission, etc).

How to configure nginx rules so that if one failed it serve the request using another

Note, this question is moved to stackoverflow from superuser
I got the following nginx conf:
server {
listen 80;
listen 443 ssl;
...
# specific rule to serve versioned js resources
location ~ ^/js/([0-9\.]+)/(.*)$ {
alias /opt/x/public/deploy/js/$1/$2;
}
location / {
add_header P3P 'CP="CAO PSA OUR"';
proxy_pass http://127.0.0.1:8088;
set $ssl off;
if ($scheme = https) {
set $ssl on;
}
proxy_set_header X-Forwarded-Ssl $ssl;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
It works as expected. However if a certain versioned js resource does not exists in the deployed dir, say /opt/x/public/deployed/js/1.1/, it will return 404. What I want is in that case nginx shall pass the request to the backend service running at 8088 port instead of returning 404. Is this even doable?
Thanks!
Green
http://wiki.nginx.org/HttpCoreModule#try_files
try_files is your friend, here you can do the order you want to try files and finaly have the proxypass upstream.

nginx subdomain to directory , too many redirect , why?

this is my config:
server {
listen 80;
server_name ~^(?<sb>.+)\.a\.b\.c\.com$;
access_log /data/logs/nginx/tas.access.log main;
location / {
proxy_intercept_errors on;
proxy_pass http://b.c/a/$sb/;
proxy_set_header Host $host;
proxy_redirect off;
}
}
and browser report to many redirects.
If, as you say, you want to proxy to localhost:8082, you need to say so in the proxy_pass line:
server {
listen 80;
server_name ~^(?<sb>.+)\.a\.b\.c\.com$;
access_log /data/logs/nginx/tas.access.log main;
location / {
proxy_intercept_errors on;
proxy_pass http://localhost:8082/a/$sb/;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Without all of the information, it's hard to guess what's going on. Based on the comments, my guess is that you are using virtual hosting so that the upstream site is also served by the same nginx. So this line is the problem:
proxy_set_header Host $host;
The nginx variable $host is pointing to the current Host header (which matches the server_name). So if you set the same host header for the upstream again, then nginx will find the same location block above because nginx relies on the Host header to find the proper server. Thus the redirect loop.
Set
proxy_set_header Host your_upstream_server_name
will fix it then.

Resources