Configure URL Rewriting for Framework-Based PHP Applications on IBM Bluemix

A few weeks ago, I was introduced to Bluemix, IBM’s new cloud infrastructure platform for developers. With a bunch of pre-configured runtimes for Java, Node.js and Ruby, plus MongoDB, MySQL and various other database services, BlueMix provides a platform for quick app development and deployment.

Bluemix is currently in beta and doesn’t support PHP (yet) but I found a blog post which suggested it was possible using the Zend Server PHP buildpack. However, on trying it, I came across a problem: my Web application (built with Slim Framework) needed URL rewriting for its custom routes to work, but I couldn’t find a way to edit the nginx configuration file included with the Zend Server PHP buildpack. The search for an alternative led me (via Q&A in this thread) to the Cloud Foundry PHP buildpack, which solved my problem.

In case you’re looking to run a PHP application on Bluemix and you need URL rewriting (or other server-level modifications to configuration), here are the steps I followed:

1. Use the application manifest to load the Cloud Foundry PHP buildpack.
The application manifest file manifest.yml tells the Cloud Foundry CLI how to deploy the application, including which buildpack to use. Here’s what I used.

myapp/manifest.yml:
---
applications:
- name: my-slim-php-app
memory: 256M
instances: 1
host: my-slim-php-app
buildpack: https://github.com/dmikusa-pivotal/cf-php-build-pack.git

2. Override default buildpack settings with your custom configuration.
The best thing about the Cloud Foundry PHP buildpack is that it lets you override default httpd, nginx and PHP configuration settings with your own. All you need to do is add a .bp-config/ directory to your application’s root, then add an options.json file with buildpack configuration variables.

By default, the buildpack will install Apache as the Web server. To use nginx instead, I made some changes.

myapp/.bp-config/options.json:
{
"WEB_SERVER": "nginx"
}

The buildpack also lets you custom-configure Apache, nginx or PHP, simply by adding your custom configuration files within a httpd/, nginx/ or php/ sub-directory. By combining the URL rewriting instructions in Slim’s documentation with the existing nginx defaults, I generated the following overrides.

myapp/.bp-config/server-defaults.conf:

listen @{VCAP_APP_PORT};
server_name _;

fastcgi_temp_path @{TMPDIR}/nginx_fastcgi 1 2;
client_body_temp_path @{TMPDIR}/nginx_client_body 1 2;
proxy_temp_path @{TMPDIR}/nginx_proxy 1 2;

real_ip_header x-forwarded-for;
set_real_ip_from 10.0.0.0/8;
real_ip_recursive on;

# ?$args or ?$query_string at the end of the next line
# tells nginx to forward query arguments
try_files $uri /index.php?$query_string;

myapp/.bp-config/server-locations.conf:

# Some basic cache-control for static files to be sent to the browser
location ~* \.(?:ico|css|js|gif|jpeg|jpg|png)$ {
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}

# Deny hidden files (.htaccess, .htpasswd, .DS_Store).
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}

# modified from Slim documentation
# pass *.php to the fastcgi process
location ~ .*\.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php_fpm;
}

3. Push your application code to Bluemix.

cf api https://api.ng.bluemix.net
cf login
cf push

That’s pretty much all there is to it. You should now be able to access your Slim routes without any problems. These settings should also work (with minor changes) for other framework-based PHP applications, including those written with BulletPHP, Zend Framework and Agavi.

If you prefer Apache, this thread explains how to set up the necessary URL rewriting rules for Apache. If you don’t have a Bluemix account, you can request one here.