Nginx reverse proxy configuration for multiple domains - apache

I have multiple accounts/domains on my server. I'm using cPanel with Apache 2.4 and wanted to use Nginx as a front reverse proxy. I changed Apache port, installed Nginx and it works fine but for one domain/account only. I want to use it for all my domains on the server, and any future accounts. I tried to enter $domain variable instead of a specific domain but realized later that nginx doesn't support variables. Same thing with the user directory. Here is my config file:
user nobody;
worker_processes 4;
error_log logs/error.log crit;
worker_rlimit_nofile 8192;
events {
worker_connections 1024; # you might need to increase this setting for busy servers
use epoll; # Linux kernels 2.6.x change to epoll
}
http {
server_names_hash_max_size 2048;
server_names_hash_bucket_size 512;
server_tokens off;
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 10;
# Gzip on
gzip on;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_types text/plain application/x-javascript text/xml text/css;
# Other configurations
ignore_invalid_headers on;
client_max_body_size 8m;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
connection_pool_size 256;
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
request_pool_size 4k;
output_buffers 4 32k;
postpone_output 1460;
# Cache most accessed static files
open_file_cache max=10000 inactive=10m;
open_file_cache_valid 2m;
open_file_cache_min_uses 1;
open_file_cache_errors on;
# virtual hosts includes
include "/etc/nginx/conf.d/*.conf";
server {
# this is your access logs location
access_log /usr/local/apache/domlogs/accountusername/example.com;
error_log logs/vhost-error_log warn;
listen 80;
# change to your domain
server_name example.com www.example.com;
location ~* \.(gif|jpg|jpeg|png|wmv|avi|mpg|mpeg|mp4|htm|html|js|css)$ {
# this is your public_html directory
root /home/accountusername/public_html;
}
location / {
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 16 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_connect_timeout 30s;
# change to your domain name
proxy_redirect http://www.example.com:8080 http://www.example.com;
proxy_redirect http://example.com:8080 http://example.com;
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
What I'm trying to do is to place a code that works for all domains on the server and any future domains will be added. I see some forums and blogs explain to setup virtual hosts (Server blocks) but I'm not sure what they're used for. I'd appreciate it if anyone provide any info about this. Should I setup virtual hosts? What is needed to be changed in my configuration file? Thank you.

You config is almost correct
server {
listen frontip:80 default_server;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect http://$host:8000/ http://$host/;
}
}
But best way to you do not use 8080 port. All you need is tell to nginx to bind only external ip. Add ip and bind keyword to all your listen in each server.
server {
listen frontip:80 default_server bind;
location / {
proxy_pass http://127.0.0.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
If you missed nothing, nginx will not bind 127.0.0.1:80, so apache can bind it.
In this case you do not need any proxy_redirect directives because you don't need any redirect rewrites.
For root folder you can use variables but much better use map;
http {
...
map $host $root {
hostnames;
default /var/www;
.domain1.com /home/user1/domain1.com;
custom.domain1.com /home/user1/custom;
domain2.com /home/user2/domain2.com;
www.domain2.com /home/user2/domain2.com;
}
server {
listen frontip:80 default_server;
root $root;
location / {
proxy_pass http://127.0.0.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location ~* \.(gif|jpg|jpeg|png|wmv|avi|mpg|mpeg|mp4|htm|html|js|css)$ {
}
}
}
More about map http://nginx.org/en/docs/http/ngx_http_map_module.html

Your idea is a kind of fantastic. To operate in good and predictable\debuggable way, you should create "server" block for every server you serve, and you should write it domain name into "proxy_redirect" directive accordingly.
To handle a lot of domains - get a list of them and write shell\perl\python script to generate your actual config. This script will be rather simple one.
And read the docs - to understand clearly what "server blocks" are for. Shortly, they are the core of nginx's performance magic.

Related

How to handle multiple hostnames handles from nginx to apache in the same server?

I have the plan to manage multiple websites on the same server and I'm currently handling the http request from nginx then handling it to apache.
This is what the configuration I currently have for my first website:
# Force HTTP requests to HTTPS
server {
listen 80;
server_name myfirstwebsite.net;
return 301 https://myfirstwebsite.ne$request_uri;
}
server {
listen 443 ssl;
root /var/opt/httpd/ifdocs;
server_name myfirstwebsite.ne ;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000" always;
ssl on;
ssl_certificate /etc/pki/tls/certs/cert.pem;
ssl_certificate_key /etc/pki/tls/certs/cert.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/iflogs/http/access.log;
error_log /var/log/nginx/iflogs/http/error.log;
###include rewrites/default.conf;
index index.php index.html index.htm;
# Make nginx serve static files instead of Apache
# NOTE this will cause issues with bandwidth accounting as files wont be logged
location ~* \.(gif|jpg|jpeg|png|wmv|avi|mpg|mpeg|mp4|htm|html|js|css)$ {
expires max;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:4433;
}
# proxy the PHP scripts to Apache listening on <serverIP>:8080
location ~ \.php$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:4433;
}
location ~ /\. {
deny all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Now, My question is, for the second, third website and so on, I'm thinking in modifying the line:
proxy_pass https://127.0.0.1:4433;
for
proxy_pass https://secondwebsite.net:4433;
but what I don't want to do is that the goes out of the internet and looks up for that dns and then comes back to the same server, but serve in the same server (which is why I had localhost:4433 in the first website), so I don't get latency issues.
Is there any solution for this?
Also, I want to know if there will be issues if I serve multiple servers using the same port (in this case 4433) or do I have to use a different port for each website.
Thank you in advance.
Multiple server confs
One way to do this would be to have multiple server blocks, ideally over different conf files. Something like this would do for your second server in a new file (e.g. /etc/nginx/sites-available/mysecondwebsite):
# Force HTTP requests to HTTPS
server {
listen 80;
server_name mysecondwebsite.net;
access_log off; # No need for logging on this
error_log off;
return 301 https://mysecondwebsite.net$request_uri;
}
server {
listen 443 ssl;
root /var/opt/httpd/ifdocs;
server_name mysecondwebsite.net ;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000" always;
ssl on;
ssl_certificate /etc/pki/tls/certs/cert.pem;
ssl_certificate_key /etc/pki/tls/certs/cert.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/iflogs/http/access.log;
error_log /var/log/nginx/iflogs/http/error.log;
###include rewrites/default.conf;
index index.php index.html index.htm;
# Make nginx serve static files instead of Apache
# NOTE this will cause issues with bandwidth accounting as files wont be logged
location ~* \.(gif|jpg|jpeg|png|wmv|avi|mpg|mpeg|mp4|htm|html|js|css)$ {
expires max;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:4434;
}
# proxy the PHP scripts to Apache listening on <serverIP>:8080
location ~ \.php$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:4434;
}
location ~ /\. {
deny all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
You would then create a symlink using ln -s /etc/nginx/sites-available/mysecondwebsite /etc/nginx/sites-available/ and restart nginx. To answer your question about ports, you can only have one TCP application listening on any single port. This post provides a few more details about that.
You could also define an upstream in your server block like so:
upstream mysecondwebsite {
server 127.0.0.1:4434; # Or whatever port you use
}
And then reference this upstream using proxy pass like so:
proxy_pass http://mysecondwebsite;
This way if you change the port, you will only have to change it in one place in your server conf. Also, this is how you would scale your application with multiple Apache servers and implement load balancing.

Nginx 2 webservers behind 1 IP

I have 2 web servers plus the nginx server as a reverse proxy. call them web1 web2 and nginx1.
web1 10.0.0.110 with abc.com, def.com
web2 10.0.0.120 with hij.com, klm.com
nginx1 10.0.0.125
Im trying to have 2 webservers behind 1 external IP
I have nothing in /etc/nginx/conf.d/
I have created conf files for each site in sites-available and linked them with symlinks to sites-enabled.
example file.
server {
listen 80;
server_name *.abc.com;
access_log off;
error_log off;
location / {
proxy_pass http://10.0.0.110/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_max_temp_file_size 0;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}
The problem is its not working correctly, it seems to want to direct all the sites to either server, it seems to be dependent on the last conf file I edit.
What am I doing wrong?
You'll need to provide a server directive per backend webserver. Here's an example of what should work for you (replacing the ellipsis with your additions):
server {
server_name abc.com def.com;
...
location / {
proxy_pass http://10.0.0.110/;
...
}
}
server {
server_name hij.com klm.com;
...
location / {
proxy_pass http://10.0.0.120/;
...
}
}
I believe i have it sorted, i needed to have the IP set
listen 10.0.0.125:80
And set the domain name correctly *.abc.com doesn't include abc.com, it only included all the subdomains.
so I changed it to
server_name .abc.com;
Just making one of these changes didn't solve my problem.

nginx doesn't serve static assets in Rails 3

Stackoverflowers. I have a problem with my Rails nginx configuration. I'm running a Rails 3.0.12 app, and I'm quite new to nginx.
I can't seem to get nginx to serve static assets. For every request in /public folder I get 404. I'm posting the nginx configuration I got so far. Maybe I missed something
nginx.conf:
user rails;
worker_processes 1;
daemon off;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 2048;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
server_names_hash_bucket_size 64;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
sites-enabled/project.conf:
upstream project {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response (in case the Unicorn master nukes a
# single worker for timing out).
# for UNIX domain socket setups:
server unix:/tmp/project.socket fail_timeout=0;
}
server {
listen 80;
root /srv/www/project/current/public;
passenger_enabled on;
server_name dev.project.eu;
server_name *.dev.project.eu;
location / {
#all requests are sent to the UNIX socket
proxy_pass http://project;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
root /srv/wwww/project/current/public;
}
}
I've tried removing the location / block from project.conf, but it didn't do anything, the assets are still not visible.
I am also aware of serve_static_assets switch in Rails, but I'd rather have nginx serve those assets, as it should do so.
You need to add something like that (documentation on locations):
location / {
try_files $uri #ruby;
}
location #ruby {
proxy_pass http://project;
}
I know this thread is over a year old but i had the same problem running in production
The thing that made it work for me was running
rake assets:precompile
in development, and uncommenting
load 'deploy/assets'
even though I am using rails 4.

Trouble getting SSL to work with django + nginx + wsgi

I've followed a couple of examples for Django + nginx + wsgi + ssl, but I can't get them to work. I simply get an error in my browser than I can't connect.
I'm running two websites off the host. The config files are identical except for the ip addresses, server names, and directories.
When neither use SSL, they work fine. When I try to listen on 443 with one of them, I can't connect to either.
My config files are below, and any suggestions would be appreciated.
server{
listen xxx.xxx.xxx.xxx:80;
server_name sub.domain.com;
access_log /home/django/logs/nginx_customerdb_http_access.log;
error_log /home/django/logs/nginx_customerdb_http_error.log;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
}
location /site_media/ {
alias /home/django/customerdb_site_media/;
}
location /admin-media/ {
alias /home/django/django_admin_media/;
}
}
server{
listen xxx.xxx.xxx.xxx:443;
server_name sub.domain.com;
access_log /home/django/logs/nginx_customerdb_http_access.log;
error_log /home/django/logs/nginx_customerdb_http_error.log;
ssl on;
ssl_certificate sub.domain.com.crt;
ssl_certificate_key sub.domain.com.key;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Protocol https;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
}
location /site_media/ {
alias /home/django/customerdb_site_media/;
}
location /admin-media/ {
alias /home/django/django_admin_media/;
}
}
<VirtualHost *:8080>
ServerName xxx.xxx.xxx.xxx
ServerAlias xxx.xxx.xxx.xxx
LogLevel warn
ErrorLog /home/django/logs/apache_customerdb_error.log
CustomLog /home/django/logs/apache_customerdb_access.log combined
WSGIScriptAlias / /home/django/customerdb/apache/django.wsgi
WSGIDaemonProcess customerdb_wsgi processes=4 threads=5
WSGIProcessGroup customerdb_wsgi
SetEnvIf X-Forwarded-Protocol "^https$" HTTPS=on
</VirtualHost>
UDPATE: the existence of two sites (on separate IPs) on the host is the issue. if i delete the other site, the setting above mostly work. doing so also brings up another issue: chrome doesn't accept the site as secure saying that some content is not encrypted.
[This should actually be a comment ...]
You should also set
proxy_set_header X-Forwarded-Protocol $scheme
To indicate to Django when connections are secure, otherwise your https links will get redirected to http, which is bad.
This will set http when it actually is http, and https when it's https.
I changed the server that listens on 80 to rewrite to https removed all the other directives.

Apache and ultimate config for nginx to serve all virtual hosts in the right way

I've just set up nginx to serve static request on one site, but I have lots of sites on my server and I wonder, should I right new nginx server configuration for all of them?
What I'm doing now. I have file with all virtual hosts entries for Apache with some-thing like this:
NameVirtualHost *:8080
<VirtualHost *:8080>
ServerName sky2high.net
DocumentRoot /home/mainsiter/data/www/sky2high.net
</VirtualHost>
<VirtualHost *:8080>
ServerName surdo.asmon.ru
DocumentRoot /home/surdo/data/www/surdo.asmon.ru
</VirtualHost>
<VirtualHost *:8080>
ServerName surdoserver.ru
DocumentRoot /home/surdo/data/www/surdoserver.ru
</VirtualHost>
I have this in apache's ports.conf:
Listen 8080
And so I've set up nginx to work with one site (sky2high.net), created next configure file (/etc/nginx/sites-enabled/sky2high.net):
server {
listen 80;
server_name sky2high.net www.sky2high.net;
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
access_log /var/log/nginx.access_log;
location ~* \.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|tar|wav|bmp|rtf|swf|ico|flv|txt|xml|docx|xlsx)$ {
root /home/mainsiter/data/www/sky2high.net/;
index index.php;
access_log off;
expires 30d;
}
location ~ /\.ht {
deny all;
}
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
proxy_set_header Host $host;
proxy_connect_timeout 60;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_redirect off;
proxy_set_header Connection close;
proxy_pass_header Content-Type;
proxy_pass_header Content-Disposition;
proxy_pass_header Content-Length;
}
}
And it works fine for this domain, but of course another virtual hosts are broken.
So, the question is: is there ultimate config option for nginx, witch can help to handle all request, from all virtual hosts (domains) and serve them in the right way? I mean, option that allows not to write separete configure files for each virtual hosts (with all this doubled stuff like root and index options), but only one for all virtual hosts?
PS: should I move question to serverfault?
UPDATE:
Emm.. I wonder how is it works, but it is. I've made next config files:
/etc/nginx/nginx.conf
user www-data;
worker_processes 2;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
gzip on;
gzip_min_length 1000;
gzip_proxied any;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
and
/etc/nginx/sites-enabled/default
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection close;
proxy_pass_header Content-Type;
proxy_pass_header Content-Disposition;
proxy_pass_header Content-Length;
}
}
I do not understand how is it works, but it is...
UPDATE 2: or it doesn't work! I've looked to "top" in console and metioned that apache serves not only php request, but for static content either =(
What you do now is sending all the network traffic to 127.0.0.1:8080 without allowing Nginx to serve the static files.
What you should try is the following:
server {
listen 80;
server_name sky2high.net www.sky2high.net;
location / {
proxy_pass http://127.0.0.1:8080;
include /etc/nginx/conf.d/proxy.conf;
}
location ~* ^.+\.(jpg|jpeg|gif|png|ico|tgz|gz|pdf|rar|bz2|exe|ppt|txt|tar|mid|midi|wav|bmp|rtf) {
root /folder/to/static/files;
expires 90d;
}
location ~* ^.+\.(css|js)$ {
root /folder/to/static/files;
expires 30d;
}
And in proxy.conf you put the following:
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 8m;
client_body_buffer_size 256k;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 32 256k;
proxy_busy_buffers_size 512k;
proxy_temp_file_write_size 256k;
This should work for you
Just my two cents, in most cases it's not necessary to specify the listen 80.
Source: Nginx common Pitfalls