2

I'm using nginx as web front-end and apache2 as web back-end. Apache runs several websites locally and nginx access them.

At the moment, different sub-domains are hosted, but I want to migrate them into a single one using http://my-single-domain.com/subdomain-alias thanks to nginx.

The root directory and the apache2 vhost port is different for each sub-domain (sounds obvious, doesn't it?).

I tried several configurations but I cannot get the resource being sent, i.e., the index html is sent but the resources are not found by the server (404 Not Found) despite the rule root being set.

I tried several solution such as:

location /alias1 {
  proxy_pass   http://127.0.0.1:9095/;
  include      /etc/nginx/proxy.conf;
}

or

location /alias1 {
  alias  /alias1/;
  proxy_pass   http://127.0.0.1:9095/;
  include      /etc/nginx/proxy.conf;
}

or even

location /alias1/ {
  rewrite ^/alias1(/.*)$ $1 break;
  proxy_pass http://127.0.0.1:9095/;
}

or again

location /alias1/ {
  rewrite ^/alias1(/.*)$ $1 break;
  proxy_pass   http://127.0.0.1:9095/;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

What is wrong with this setup? How to set nginx to retrieves assets from a specific root directory when the age /alias1/page is requested ?


Asked first on webmasters.stackexchange.com

---### /etc/nginx/proxy.conf 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-Proto 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;

/etc/nginx/nginx.conf

 user              www-data  www-data;

 worker_processes  2;

 pid        /var/run/nginx.pid;

 worker_rlimit_nofile 1024;

 events {
         worker_connections 512;
 }


 http {

         include /etc/nginx/mime.types;
         default_type application/octet-stream;
         sendfile "on";
         tcp_nopush "on";
         tcp_nodelay "on";
         keepalive_timeout "65";
         access_log "/var/log/nginx/access.log";
         error_log "/var/log/nginx/error.log";
         server_tokens off;
         types_hash_max_size 2048;

         include /etc/nginx/conf.d/*.conf;
         include /etc/nginx/sites-enabled/*/*;
 }

/etc/nginx/site-enable/single-domain.conf

server {
        listen      443;
        ssl on;
        ssl_certificate /etc/ssl/private/single-domain.com-with_chain.crt;
        ssl_certificate_key /etc/ssl/private/single-domain.com.key.pem;

        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        ssl_prefer_server_ciphers on;
        ssl_dhparam /etc/ssl/private/dhparams.pem;

        server_name www.single-domain.com;

        location / {
                proxy_pass   http://127.0.0.1:8090/;
                include      /etc/nginx/proxy.conf;
        }

        location /alias/ {
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_pass   http://127.0.0.1:8103/;
        proxy_set_header Host alias.single-domain.com;
        root /var/www/alias.single-domain.com;
        }

        location ~* \.(jpg|png|gif|jpeg|css|js|mp3|wav|swf|mov|doc|pdf|xls|ppt|docx|pptx|xlsx|otf|eot|svg|ttf|woff)$ {
                root /var/www/single-domain.com/public;
                proxy_buffering on;
                proxy_cache_valid 200 120m;
                expires 864000;
        }

        access_log /var/log/nginx/single-domain.com/www-access.log;
        error_log /var/log/nginx/single-domain.com/www-error.log;
}
Auzias
  • 79
  • 1
  • 1
  • 7
  • It's really bad idea. You'll have to modify all your websites to look for static assets not in `/img/logo.png` but `/alias1/img/logo.png`. It could be sometimes nearly impossible. – Alexey Ten Mar 04 '16 at 14:09
  • Why you want get rid of subdomains? – Alexey Ten Mar 04 '16 at 14:10
  • The goal is not to get rid of the subdomains, but use the TLS of the single domain instead. The subdomains are just personal and private services that, IMO, do not need subdomains for that in the first place (just that it ease to separate them in the first place). Isn't it possible to request nginx to search assets into another root directory while removing the `/alias/`-part-path of the asset itself ?! – Auzias Mar 04 '16 at 14:14
  • Just get wildcard cert! Willl be valid for all sub domains. May cost you a little more but will save you a lot of time!! Changing away from sub domains will also have major SEO implications. Don't make such a major change if all your gaining is saving a few bucks on your SSL cert – Nath Mar 06 '16 at 18:58
  • As I said, it's personal and private services that are hosted. I do not need any valid cert while it's a plus. I'm well aware of this solution, that I do not seek (otherwise I would have asked where to buy a wild-card cert, not how to config nginx. Thanks for the comment though. – Auzias Mar 06 '16 at 19:44
  • post complete configuration, all files please, including /etc/nginx/proxy.conf, according to what i see, you've got something wrong in your configs :) also, include apache configuration for vhosts. – GioMac Mar 12 '16 at 04:59
  • Conf file added in the question. – Auzias Mar 12 '16 at 11:59

1 Answers1

2

If apache is listening on port 9095 for domain sub1.example.com and on port 9096 for domain sub2.example.com, and you want nginx to pass http://www.example.com/alias1 to first, and http://www.example.com/alias2 to second apache virtualhost, you would do:

location /alias1/ {
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_pass   http://127.0.0.1:9095/;
        proxy_set_header Host sub1.example.com;
}

location /alias2/ {
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_pass   http://127.0.0.1:9096/;
        proxy_set_header Host sub2.example.com;
}

then for example original request to nginx at http://your-single-domain.example.com/alias1/foo/page1.html would be forwarded to apache as if it went to http://sub1.example.com:9095/foo/page1.html

And original request to nginx at http://your-single-domain.example.com/alias2/bar/baz/page2.html would be forwarded to apache as if it went to http://sub2.example.com:9096/bar/baz/page2.html

Update1 (proof of concept): with the nginx having only config file as above, we run netcat as nc -l -p 9095 (apache should not be listening on that port for this debug), and then open in browser http://www.single-domain.com/alias1/assets/style.css. We should see in netcat output the following:

GET /assets/style.css HTTP/1.1
Host: sub1.example.com
Connection: close
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.6.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1

If there was apache listening on port 9095 instead of our netcat, it would thus get HTTP/1.1 request for URL "http://sub1.example.com/assets/style.css" (which would be shown in /var/log/apache2/access_log or similar)

Note that rewrite ^/alias1(/.*)$ $1 break; isn't needed, as location /alias1/ will automatically strip that /alias1/ part of URL.

If you get different output when using your nginx config file, that means you have conflicting directives in nginx - I that case recommend starting with just the configuration in this answer, checking that it works, and then start adding old configuration blocks one by one until it breaks - and then you'll have conflicting block which needs to change.

Update2: since you posted your nginx config, it is obvious - you have location override that says all your .css files (along the bunch of other files) are to be served directly with nginx from /var/www/single-domain.com/public. Remove or edit it, and it will go through apache.

Matija Nalis
  • 2,478
  • 24
  • 37
  • Thanks for your answer! I tried this conf but the assets are still fetched on `http://www.single-domain.com/alias1/assets/style.css` and not `http://alias1.single-domain.com/assets/style.css`. – Auzias Mar 10 '16 at 07:56
  • @Auzias are you sure you don't have some *other* directives in nginx configuration and that you've successfully restarted it? `location /alias1` should *always* match `http://www.single-domain.com/alias1/assets/style.css` (if nginx is listening on www.single-domain.com, of course!) and thus should always get to apache via specified proxy. – Matija Nalis Mar 11 '16 at 02:09
  • That would explain the weird behavior. I'm positive that nginx restarted. Shouldn't a `rewrite ^/alias1(/.*)$ $1 break;` be added? – Auzias Mar 11 '16 at 09:29
  • @Auzias see the updated answer; rewrite isn't needed in this case (it would be needed only if you used "location /" instead of "location /alias1") – Matija Nalis Mar 12 '16 at 20:56
  • Hi again, you were actually right! The directive `location ~* \.(jpg|...)${ root /var/www/path/to/single-domain` sets nginx to fetch every `~*\.(jpg|png|css...` in the directory of the `single-domain`. I guess I have to add a `if` within this location directive. Or is there a cleaner way to deal with that? – Auzias Mar 13 '16 at 13:40
  • @Auzias unless you actually **WANT** to have nginx serve files directly from `/var/www/single-domain.com/public`, you should DELETE that whole block from `location ~* \.(jpg .... ` until `}`. But if your want SOME files to be served from there, but not others, then you should modify the regexp (for example, if you remove just `|css` part, CSS would be proxyed to apache, but other file extensioned mentioned in regex wouldn't. But you must first decide what you actually want. – Matija Nalis Mar 13 '16 at 15:09
  • I think I'll work around this and keep it while using a better regexp to differentiate different website assets (so nginx still acts as a proxy cache). – Auzias Mar 13 '16 at 15:14
  • @Auzias if proxy buffering is only thing which you want from nginx, then you should remove `root /var/www/single-domain.com/public` in that block. Than it will still pass requests to apache, but will cache them afterwards if (and only if) they match the regexp. – Matija Nalis Mar 13 '16 at 20:22
  • Using the `root` directive enables nginx to fetch the resource itself. Hence it avoids the resources being passed through the local IP stack which a performance gain. That's the reason I still want to keep it. – Auzias Mar 14 '16 at 06:46
  • @Auzias Sure, there is performance improvement, but it is **absolutely minuscule**. Let's say nginx can fetch a CSS file in 0.001 second, while apache is so terribily overloaded that is will 1000 times more (whole 1 second). (Note that difference will be much less in real life). That difference *only* comes into play if the resource is not cached by nginx (set to **120m** currently). So in absolutely best case, you will save 0.999 seconds every 2 hours. Which is speed improvement of 0.999/7200 or about 0.01% - thousands of times too small for any human to ever notice. – Matija Nalis Mar 14 '16 at 15:33