Archive for November 22, 2010

Multiviews in nginx (sorta)

I use wsvn on my svn subdomain. Nginx doesn’t have real support for this, but there is a way to sorta do this.

First we set this in our / location:

                #Sorta emulate multiviews.
                set $path_info "";
                if ($uri ~ "^/wsvn/(.+)$")
                {
                        set $path_info "/$1";
                        rewrite ^(.+)$ /wsvn.php?$1 last;
                }

Now I just need to let fastcgi know this. My fast cgi params are in their own file, but this is the only thing that uses this. So I do not bother with adding it into the params file. I just define it after my SCRIPT_FILENAME param is defined.

                fastcgi_param  PATH_INFO $path_info;

That gets it working.. However, I ran into two issues so far while working with this.
1. when trying to view a file that has a .php extension, it will try to run that through fastcgi. You can’t use fastcgi inside of a if statement. So there is no way I could see to resolve this. This is actually my breaking point of using nginx to serve my wsvn pages.
2. For some reason, it urlencodes the data in PATH_INFO. Apache when it sets this, does not (spaces are not converted to %20). I had to modify the wsvn code that used multiviews and told it to urldecode() the path info before it handled it elsewhere in the script.

Maybe somebody else who knows more about nginx can resolve these two issues. I would be glad to hear anything about it.

Update:
After more working, I did find a solution for the php issue. Not a nice solution, but it gets around the issue. The urlencode issue still exists. But a minor change to my wsvn.php to fix this was no biggie.

Update 2:
I did locate a solution on nginx’s website. Although I found it by chance.

http://wiki.nginx.org/HttpFcgiModule#fastcgi_split_path_info

However, I would like to note while this solution would work, it would fail still if a .php exist in the url.

I am including my current entire config for my svn sub domain just to show how its being done. I know some things can be done better and would love to hear thoughts.

I should note that the note at the top is what I am using as reference for what ports fastcgi ports I can use on this virtualhost. Since each php configuration needs its own .ini file, I need a simple way to know what ports to be using.

# FastCGI Ports: 9050 - 9059
server
{
	listen   443;
	server_name  svn.sleepycode.com;

	ssl on;
	ssl_certificate  /home/certs/svn.sleepycode.pem;
	ssl_certificate_key  /home/certs/svn.sleepycode.key;
	ssl_session_timeout  5m;

	access_log  /var/log/nginx/svn.sleepycode.com-.access.log;
        error_log  /var/log/nginx/svn.sleepycode.com-error.log;

	## TODO: test this :P
	location /code
	{
		proxy_pass      http://svn.sleepycode.com:8999;
		include         /etc/nginx/proxy.conf;
		set  $dest  $http_destination;
		proxy_set_header  Destination   $dest;
	}

	location /
	{
		root   /home/sites/svn.sleepycode.com/public_html;
		index  index.php;

		location /wsvn/
		{
			# Sorta emulates multiviews.
			set $path_info "";
			if ($uri ~ "^/wsvn/(.+)$")
			{
				set $path_info "/$1";
			}

			include /etc/nginx/fastcgi_params;
			fastcgi_pass   127.0.0.1:9050;
			fastcgi_index  wsvn.php;
			fastcgi_param  SCRIPT_FILENAME  /home/sites/svn.sleepycode.com/public_html/wsvn.php;
			fastcgi_param  PATH_INFO $path_info;
			fastcgi_param  SCRIPT_NAME /wsvn;

			# Some reason php files still don't work, this is a solution?
			location ~ \.php$
			{
				set $path_info "";
				if ($uri ~ "^/wsvn/(.+)$")
				{
					set $path_info "/$1";
				}

				include /etc/nginx/fastcgi_params;
				fastcgi_pass   127.0.0.1:9050;
				fastcgi_index  wsvn.php;
				fastcgi_param  SCRIPT_FILENAME  /home/sites/svn.sleepycode.com/public_html/wsvn.php;
				fastcgi_param  PATH_INFO $path_info;
				fastcgi_param  SCRIPT_NAME /wsvn;

				break;
			}
		}
	}

	# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
	#
	location  ~ \.php$
	{
                include /etc/nginx/fastcgi_params;
                fastcgi_pass   127.0.0.1:9050;
                fastcgi_index  wsvn.php;
                fastcgi_param  SCRIPT_FILENAME  /home/sites/svn.sleepycode.com/public_html/$fastcgi_script_name;
		fastcgi_param  PATH_INFO $path_info;
                #includefastcgi_params;
        }

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	location ~ /\.ht
	{
		deny  all;
	}
}

Disabling php files in wordpress upload when using nginx

This isn’t well documented anywhere for nginx. In fact it is sorta hidden and hard to find. Nginx does support a way for me to disable php from being executed in my uploads directory.
The way I came across actually I am loving, as I am able to control how content is handled actually. This is a plus on the server admins end.

                # Only allow images to be viewed.
                location /wordpress/wp-content/uploads/
                {
                        types
                        {
                                image/gif       gif;
                                image/jpeg      jpeg jpg;
                                image/png       png;
                                text/plain      txt;
                        }

                        default_type    application/octet-stream;

                        location ~ \.php$
                        {
                                break;
                        }
                }

Simply put, I setup a location to only run on my uploads directory. Then I change the types and only defined jpg, gif and png. All other files get sent as a download. Finally since I run php as fastcgi, I setup a nested location to run for php files and tell it to stop evaluating rules.

In fact, this is all actually nested in my primary location /. I did it this way as it worked the easiest. Although I am sure I could remove that nesting.

Read more

Nginx with wordpress seo urls

I have been testing running my site with Nginx instead of Apache.  One of the issues I have ran across is getting wordpress to work right since I use the SEO urls.  Not that SEO urls make any difference, its a fun challenge to just work with.

One issue I ran across is getting these urls to work right.  After some reading, I did discover that there is a simple code for the rewrite that is used in apache.  However I couldn’t get this to work as the document examples showed.  I found out after testing, that it must exist in the location attribute.  Which is actually better for the setup.

        location / {
                root   /home/sites/sleepycode.com/public_html;
                index  index.php index.html index.htm;

                # Send a expire header for static files.
                if ($request_uri ~* "\.(ico|css|js|gif|jpe?g|png)\?[A-Za-z0-9\.-_]+$")
                {
                        expires 30d;
                        break;
                }

                # Handle wordpress pretty urls.
                if (!-e $request_filename)
                {
                        rewrite ^(.+)$ /index.php?q=$1 last;
                }
        }

This makes things work as they should.

Update:

If has been suggested by the Nginx team to be avoided.  So here is another solution that avoids if:

        # Handle wordpress pretty urls.
        location /
        {
                try_files $uri @wordpress;
        }
        location @wordpress
        {
                rewrite "^/(\d{4})/(\d{2})/(.+)$" /index.php?q=$1 last;
        }
Highslide for Wordpress Plugin