views:

988

answers:

5

I've got a standard Rails app with Nginx and Mongrel running at http://mydomain. I need to run a Wordpress blog at http://mydomain.com/blog. My preference would be to host the blog in Apache running on either the same server or a separate box but I don't want the user to see a different server in the URL. Is that possible and if not, what would you recommend to accomplish the goal?

A: 

Seems to me that something like a rewrite manipulator would do what you want. Sorry I don't have anymore details -- just thinking aloud :)

Ian P
+6  A: 

Actually, since you're using Nginx, you're already in great shape and don't need Apache.

You can run PHP through fastcgi (there are examples of how to do this in the Nginx wiki), and use a URL-matching pattern in your Nginx configuration to direct some URLs to Rails and others to PHP.

Here's an example Nginx configuration for running a WordPress blog through PHP fastcgi (note I've also put in the Nginx equivalent of the WordPress .htaccess, so you will also have fancy URLs already working with this config):

server {
    listen       example.com:80;
    server_name  example.com;
    charset      utf-8;
    error_log    /www/example.com/log/error.log;
    access_log   /www/example.com/log/access.log  main;
    root         /www/example.com/htdocs;

    include /www/etc/nginx/fastcgi.conf;
    fastcgi_index index.php;

    # Send *.php to PHP FastCGI on :9001
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9001;
    }

    # You could put another "location" section here to match some URLs and send
    # them to Rails. Or do it the opposite way and have "/blog/*" go to PHP
    # first and then everything else go to Rails. Whatever regexes you feel like
    # putting into "location" sections!

    location / {
        index index.html index.php;
        # URLs that don't exist go to WordPress /index.php PHP FastCGI
        if (!-e $request_filename) {
            rewrite ^.* /index.php break;
            fastcgi_pass 127.0.0.1:9001;
        }

    }
}

Here's the fastcgi.conf file I'm including in the above config (I put it in a separate file so all of my virtual host config files can include it in the right place, but you don't have to do this):

# joelhardi fastcgi.conf, see http://wiki.codemongers.com/NginxFcgiExample for source
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
#fastcgi_param  REDIRECT_STATUS    200;

I also happen to do what the Nginx wiki suggests, and use spawn-fcgi from Lighttpd as my CGI-spawner (Lighttpd is a pretty fast compile w/o weird dependencies, so a quick and easy thing to install), but you can also use a short shell/Perl script for that.

joelhardi
+1  A: 

I think joelhardi's solution is superior to the following. However, in my own application, I like to keep the blog on a separate VPS than the Rails site (separation of memory issues). To make the user see the same URL, you use the same proxy trick that you normally use for proxying to a mongrel cluster, except you proxy to port 80 (or whatever) on another box. Easy peasy. To the user it is as transparent as you proxying to mongrel -- they only "see" the NGINX responding on port 80 at your domain.

upstream myBlogVPS {
        server 127.0.0.2:80;  #fix me to point to your blog VPS
}

 server {
    listen       80;


    #You'll have plenty of things for Rails compatibility here

    #Make sure you don't accidentally step on this with the Rails config!

    location /blog {
        proxy_pass         http://myBlogVPS;
        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;
    }

You can use this trick to have Rails play along with ANY server technology you want, incidentally. Proxy directly to the appropriate server/port, and NGINX will hide it from the outside world. Additionally, since the URLs will all refer to the same domain, you can seemlessly integrate a PHP-based blog, Python based tracking system, and Rails app -- as long as you write your URLs correctly.

Patrick McKenzie
Agree, the fastcgi solution worked fine when keeping it on the same server, although I had to reinstall/update NGINX and php because fastcgi wasn't included initially. For a separate server, this solution seems to work well - if anyone knows of any gotchas, please add them.
Brian Deterling
Proxying will work fine for you but it brings its own set of issues. One of them is performance is a bit worse. Another is you will have to change the code on your backend server to make it aware its running behind a proxy and has to look at things like X-Forwarded-For (which is actually an ...
joelhardi
... array of IPs, not necessarily a single address b/c lots of users run behind corporate or ISP proxy servers, and you want to extract the user's actual IP if your app does something with it. Also X-Forwarded-For is a user-set value so not "trusted" -- see Apache mod_extract_forwarded for more ...
joelhardi
... info there. (Proxying is good to learn, you might use Varnish or Squid one day!) Another option besides HTTP proxy is to have FCGI listen on a port on an app box (I've set up an app cluster of PHP FCGI backends this way) -- Nginx just talks to 192.168.0.8:9001 instead of 127.0.0.1:9001. Cheers!
joelhardi
Could you help what's problem with this http://serverfault.com/questions/116589/broken-images-css-javascript-uris-in-sub-uri-in-rails-that-using-nginx-for-revers
Samnang
A: 

The answers above pretty addresses your question.

An alternative FCGI would be to use php-fpm. Docs are a tad sparse but it works well.

Jauder Ho
A: 

how does this work with SEO? does google treat this as the same site?

anon