
I’ve been using Media Temple for well over a year now, specifically the Grid Service. While it’s a great service for people looking to get hosted on a budget, it’s a bit lacking on the control side of things, and I really felt the need to move out of the cloud and into a VPS. MT’s new (ve) service is a full-on VPS with dedicated resources and above-average hardware. At $30/mo, it’s a seriously good deal for the amount of performance and control you get — but you get it at the expense of any automated controls that would normally be found in either the Grid Service or Dedicated Virtual account center administrative panels.
Since the (ve) service is about as bare-bones as a VPS gets, you get a completely raw system to work with; nothing is installed but the operating system itself, and no users exist but root — which also makes it somewhat of a true VPS, since there isn’t anything really making it provider-specific. It’s whatever you make of it. As far as I know, there are nearly identical offerings at other hosting providers like Linode and Slicehost, with varying prices throughout. Instructions for one should work on others with few if any discrepancies, so long as the OS is the same, and your server responds to localhost and not some funky proprietary identifier.
UPDATE: I’ve added a couple of small changes to the location sections of php-enabled sites to fix an issue that cropped up in upgrading to Nginx 8.x versions. Everything works fine now :)
Now we’re down to the reason for this post: I had a bit of a rough time finding guides for the particular setup that I wanted. I didn’t want Apache, I wanted Nginx. I had several sites that needed hosting, and I only wanted to run a 512MB server — so I didn’t really want to waste the RAM on Apache and its propensity for rolling memory-binges.
I had read that Nginx, being significantly stripped down in comparison to Apache, keeps its memory-footprint low and steady — regardless of traffic since it’s asynchronous. It’s also extremely simple to configure (and reconfigure) on a whim. While I was able to find plenty of discussion about setting up nginx to act as a static-file proxy for a back-end Apache install, I didn’t find much in the way of using nginx as the primary server in a typical stack that needs to serve dynamic content like blogs and other CMS-driven sites. This was a problem, since WordPress/Drupal/Textpattern/(just name a CMS) all tend to hinge on the presence of Apache and its .htaccess files, unless you plan on using permalinks that begin with a question mark.
In my search, I kept seeing comments in forums to the effect of “why not just run it as a front-end proxy, and let Apache do what it does best — serve PHP and stuff?” That’s a pretty weak-sauce attitude to take, since there’s no reason Nginx shouldn’t be able to process its own PHP requests and serve static files at the same time. In fact, Nginx does a damn good job of processing PHP requests, especially when using PHP-FPM. In the end, I had to pull together information from a dozen or so different guides, forum discussions, and wikis, but it came out fantastically well by the time I was done.
From this point forward, I’ll go ahead and assume that you have at least basic experience using the Linux command line, that you’ve used Nano, a command-line text editor, and that you know how to use SSH to shell into a remote system. Both Nano and SSH are easy enough to learn about by using their respective man-pages, just use “man nano” or “man ssh” in your own terminal to learn their correct usages. We’ll also be skipping mail setup in this guide, because it turns out that setting up mail on a server is more complicated than anything else. That will be saved for the next guide.
As I mentioned before, we’re coming into this setup with a brand new Ubuntu 10.04 Linux install, a root login, and nothing more. First thing we have to do after shelling in is add a working user, then grant him sudo privileges. Of course, you’ll probably want to name him something other than user1.
The visudo command will open up the /etc/sudoers file. All you need to do to grant sudo privileges to user1 is to add a line beneath root’s, so that it looks like this:
Now kill your SSH connection as root, so we can log back in as user1 and do things the safe way.
Once you shell back in as the new user, the first thing you want to do is update your OS and grab the essential development packages (like GCC, etc.).
A note for Media Temple (ve) users: During the update, you may get a notice that /etc/init/mountall.conf has been altered, and given the option to keep the present version or update it anyway. Choose to keep your own version of the file.
user1@ve:~$ sudo apt-get update
user1@ve:~$ sudo apt-get -u upgrade
user1@ve:~$ sudo apt-get update && sudo apt-get install build-essential
Before we go any further, we should ensure that nobody can remote-login as root. This is purely optional, but it’s good practice.
Simply change the “yes” to “no” in the line PermitRootLogin:
Now go ahead and restart ssh.
Next we want to get our firewall going, so check the rules in your iptables (they should look pretty empty).
Now that you know what an empty /etc/iptables.rules file looks like, we’ll go ahead and secure it by adding rules:
Add the rules seen in the example below so that your /etc/iptables.rules looks just like it. These rules state that outgoing connections are just fine, but all incoming traffic to any port other than 80, 443, 22 or 21 is blocked — unless it’s already been established legitimately.
*filter
# Allow loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use the lo0 interface
-A INPUT -i lo -j ACCEPT
-A INPUT -i ! lo -d 127.0.0.0/8 -j REJECT
# Accept established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow all outbound traffic
-A OUTPUT -j ACCEPT
# Allow HTTP and HTTPS connections
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
# Allow SSH/SFTP
# Change the value 22 if you are using a non-standard port
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
# Allow FTP
# Purely optional, but required for WordPress to install its own plugins or update itself.
-A INPUT -p tcp -m state --state NEW --dport 21 -j ACCEPT
# Allow PING
# Again, optional. Some disallow this altogether.
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# Reject ALL other inbound
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT
Now you’ll want to make sure that your rules are put into play:
user1@ve:~$ sudo iptables-restore < /etc/iptables.rules
user1@ve:~$ sudo iptables-save < /etc/iptables.rules
Check them again to see that they’re loaded (should look quite different from the last time you did this).
user1@ve:~$ sudo iptables -L
And now finally we make sure they’re saved and reloaded at bootup:
user1@ve:~$ sudo nano /etc/network/interfaces.template
Insert “pre-up iptables-restore < /etc/iptables.rules" as the third line in the file so it looks like this:
auto lo
iface lo inet loopback
pre-up iptables-restore < /etc/iptables.rules
address 127.0.0.1
netmask 255.0.0.0
broadcast 127.255.255.255
up ip route replace 127.0.0.0/8 dev lo
Now reboot the server.
user1@ve:~$ sudo reboot
Now that the server’s secured and prepped, it’s time to finally install Nginx.
user1@ve:~$ sudo apt-get update
user1@ve:~$ sudo apt-get install nginx
user1@ve:~$ sudo /etc/init.d/nginx start
Notice we also started the server. Now try to reach either your server’s IP address or access domain in your browser. You should see the default Nginx page, letting you know that it’s up and running. If the page doesn’t resolve for the IP address, attempt to reach it through a site like Proxify.org just to be sure that it’s not a network issue on your end. If there’s still an issue, check your iptables again to be sure port 80 is open.
Next, we’re going to prep the directory where your sites will reside by adding them to the www-data group (the server’s). We’ll add your main user to the same group first, to make things run more smoothly.
user1@ve:~$ sudo usermod -a -G www-data user1
user1@ve:~$ sudo chown -R www-data:www-data /var/www
user1@ve:~$ sudo chmod -R 775 /var/www
Now your main user has group permissions for the directory where your sites will be, and so does the server.
Unless you plan on running a single website from your new Nginx-equipped server, you’ll likely want some virtual hosts. Now that your main user has /var/www privileges, it’s a good time to start using your favorite FTP app whenever it’s necessary to upload files to this directory.
We’ll start by adding one virtual host. Create a folder in your /var/www directory, then create two subdirectories named “logs” and “public” — the public directory will be root of that particular site. We’ll call the new site example.com.
You can make the site directory in one fell swoop by command line:
user1@ve:/var/www$ mkdir -p /var/www/example.com/{public,logs}
To save time, you can use this pre-made index page (zipped) to use while we set up this virtual host. Just add it to the /var/www/example.com/public directory via FTP.
Now that there’s actually a site waiting, we’ll configure the virtual host in Nginx.
user1@ve:/var/www$ sudo nano /etc/nginx/sites-available/example.com
This will create the virtual host file for Nginx in the sites-available directory. Simply paste the following into the file and change each instance of “example.com” to your site’s domain name:
server {
listen 80;
server_name www.example.com;
rewrite ^/(.*) http://example.com/$1 permanent;
}
server {
listen 80;
server_name example.com;
access_log /var/www/example.com/logs/access.log;
error_log /var/www/example.com/logs/error.log;
location / {
root /var/www/example.com/public/;
index index.html;
}
}
The first section rewrites and 301-redirects any www.example.com to example.com; the second portion tells Nginx what port to listen on for queries to this site, where to record the access and error logs, and then finally defines the location of the site’s root directory. Surprisingly simple, isn’t it? Instead of using an .htaccess file, the redirect takes place at the onset. This is the most basic virtual host configuration, but we’ll be adding more later for PHP and WordPress.
All virtual hosts’ configuration files will be kept in the /etc/nginx/sites-available directory, but won’t be enabled unless they’re symlinked in the /etc/nginx/sites-enabled directory. We’ll add the symlink now to enable example.com, then restart Nginx.
user1@ve:/var/www$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
user1@ve:/var/www$ sudo /etc/init.d/nginx restart
Now check in your browser to see if the site loads. Again, if it doesn’t resolve, use something like Proxify.org — if that works then you may want to add example.com to your own computer’s /etc/hosts file with your server’s IP address for a day or so, until the change in DNS propagates. You can try this if it doesn’t load at Proxify.org as well, since the domain itself may not have made its way through the system yet.
Assuming it worked, you should take this opportunity to check the site’s logs and make sure they’re working properly.
user1@ve:/var/www$ cat /var/www/example.com/logs/access.log
As far as setting up basic virtual hosts with Nginx is concerned, that’s it. Simply repeat the virtual host process as many times as you need to get all your domains online; they’re ready to serve static content at this point. Next we’ll set up MySQL and PHP, in preparation for dynamic content.
A note for Media Temple (ve) users: Now might be a good time to throw a command at Ubuntu to stop APT from using /tmp or /var/tmp, and to instead use /var/local/tmp — this is due to a security block that MT engineers have in place, and will ensure smoother operation in the future:
user1@ve:/var/www$ su
root@ve:/var/www# echo "APT::ExtractTemplates::TempDir \"/var/local/tmp\";" | tee /etc/apt/apt.conf.d/50extracttemplates && mkdir /var/local/tmp/
root@ve:/var/www# exit
user1@ve:/var/www$
Before we move on to install MySQL, we should take this opportunity to tune Nginx a little. Go ahead and open up /etc/nginx/nginx.conf and take a look inside.
user1@ve:/var/www$ sudo nano /etc/nginx/nginx.conf
We’re interested in the top portion of the file, where the number of Nginx worker processes and max worker connections are defined. It’s generally a good idea to make “worker_processes” anything between 1 and the number of cores in your CPU. The server I’m using has quad-core processors, so assuming I get a whole CPU to myself, I’ll go ahead and tell Nginx to have 4 worker processes. The “events” section defines the maximum number of simultaneous connections each worker process can handle. 1024 is default, and I seriously doubt you would ever need to raise it (especially when there are 4 worker processes). Each Nginx worker process uses a minuscule amount of system resources, so if you can have 4, there’s no reason not to have 4. In this setup, it’s theoretically possible to handle 4,096 simultaneous connections. The likelihood of that ever happening is fairly slim, but it does give a hell of a lot of room for the server to breathe while under more realistic loads.
user www-data;
worker_processes 4;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
# multi_accept on;
}
Now go ahead and restart Nginx, and move on.
user1@ve:/var/www$ sudo /etc/init.d/nginx restart
Installing MySQL is as easy as one command:
user1@ve:/var/www$ sudo apt-get install mysql-server php5-mysql mysql-client
You’ll be asked for a database root-user password. Use a good one! After it’s done installing we’ll log in and set up a database. Replace testdb with any database name you choose, dbuser1 with whatever username you’d like for the database user, and db_user_pw with a strong password for that user.
user1@ve:/var/www$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 162
Server version: 5.1.41-3ubuntu12.6 (Ubuntu)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database testdb;
Query OK, 1 row affected (0.00 sec)
mysql> grant all on testdb.* to 'dbuser1' identified by 'db_user_pw';
Query OK, 0 rows affected (0.00 sec)
mysql> quit
Bye
Setting up PHP turns out to be remarkably easy, and incorporating it into your Nginx virtual hosts is even easier. I grabbed this next block from a wiki page at MT. The PPA from Brian Mercer makes it short & sweet.
user1@ve:/var/www$ sudo aptitude install python-software-properties
user1@ve:/var/www$ sudo add-apt-repository ppa:brianmercer/php
user1@ve:/var/www$ sudo aptitude -y update
user1@ve:/var/www$ sudo aptitude -y install php5-cli php5-common php5-mysql php5-suhosin php5-gd
user1@ve:/var/www$ sudo aptitude -y install php5-fpm php5-cgi php-pear php5-memcache php-apc
user1@ve:/var/www$ sudo service php5-fpm start
That’s all it takes to get PHP up and running, but it’s not tuned yet. To really get the ball rolling, you want to tune your PHP to give you the best performance while not draining your server of every last bit of memory it has. Edit php5-fpm.conf to start tuning:
user1@ve:/var/www$ cd /etc/php5/fpm
user1@ve:/etc/php5/fpm$ sudo nano php5-fpm.conf
The specifics are entirely up to you, but for my 512MB server, this works pretty well. Find the lines in the file and alter to your taste, you may need to uncomment some of them.
pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 3
pm.max_requests = 500
Feel free to play with this as much as you want over the next few weeks, until you get the results you want. The file has loads of extremely helpful comments detailing what each line entails, so it’s quite painless. It’s all about compromise in the end, so find what works best for your server, your content, and your traffic volume. I prefer to keep them light, since they’ll just spawn more (up to 8) as needed. There’s also an option for emergency-restart of PHP services should your workers start faulting en masse; you may want to take a look at that as well.
Now that both MySQL and PHP are installed, it’s a good idea to go ahead and install phpMyAdmin to make life a bit easier when dealing with your databases. During the installation, you’ll be asked if you want phpMyAdmin to go ahead and set up its own database — follow the prompts and let it do what it needs to do. It’s a quick install regardless.
user1@ve:/etc$ sudo apt-get install phpmyadmin
In order to easily access phpMyAdmin, we’ll need to set up a virtual host for it. We’ll go ahead and make it a subdomain of example.com to make things simple.
user1@ve:/etc$ sudo nano /etc/nginx/sites-available/php.example.com
Paste the next block of code into that vhost file, substituting example.com wherever your own domain should be.
server {
listen 80;
server_name php.example.com;
access_log /var/log/nginx/localhost.access.log;
root /usr/share/phpmyadmin;
index index.php;
location / {
try_files $uri $uri/ @phpmyadmin;
}
location @phpmyadmin {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin/index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_NAME /index.php;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin$fastcgi_script_name;
include fastcgi_params;
}
}
Notice what we did here; we told the server to listen at port 80 for requests toward php.example.com, but instead of using a normal website’s root directory in the location block, we’ve pointed Nginx at /usr/share/phpmyadmin. The last block is something you’ll be seeing a lot more of if you host PHP-based content, because it’s the block that enables a virtual host to make use of the FastCGI server in the first place.
OK, now we want to try loading php.example.com in our browser. If all goes well, you should be able to log in just fine with your MySQL root user/pass. There’s also a decent chance that the login screen is going to say something about an error involving mcrypt — it did for me and plenty of other people as well. It’s a bit of a mystery when this happens, but the fix is easy enough. We’ll just purge and reload both the php5-mcrypt and phpMyAdmin core packages, then reboot.
user1@ve:/etc$ sudo apt-get purge php5-mcrypt phpmyadmin
user1@ve:/etc$ sudo apt-get install php5-mcrypt phpmyadmin
user1@ve:/etc$ sudo reboot
That should have fixed the issue for mcrypt, but you may still be seeing an error about pma_tracking. For some reason, phpMyAdmin seems to leave this piece of its config file out sometimes, which causes quite a bit of dismay when a user tries to log in. Luckily, it’s just the one line; it’d be much worse if we didn’t allow it to set up its database during the install. We want to make sure everything’s there, so go ahead and open up /etc/phpmyadmin/config.inc.php with Nano.
user1@ve:/etc$ sudo nano /etc/phpmyadmin/config.inc.php
About halfway down the page you’ll see a block of code where each line starts with $cfg['Servers'] — we want to make sure that the last line, ‘pma_tracking’, is there. If it isn’t (it wasn’t for me), go ahead and add it just as it appears in the example below.
/* Optional: Advanced phpMyAdmin features */
$cfg['Servers'][$i]['pmadb'] = $dbname;
$cfg['Servers'][$i]['bookmarktable'] = 'pma_bookmark';
$cfg['Servers'][$i]['relation'] = 'pma_relation';
$cfg['Servers'][$i]['table_info'] = 'pma_table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma_table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma_pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma_column_info';
$cfg['Servers'][$i]['history'] = 'pma_history';
$cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords';
$cfg['Servers'][$i]['tracking'] = 'pma_tracking';
Reboot the system.
user1@ve:/etc$ sudo reboot
Now try to load php.example.com in your browser. You shouldn’t have any errors this time, and if you have a warning about Susohin, just ignore it. Susohin hardening is a good thing and won’t likely affect anything you’ll be doing anyway.
At this point, you’ve got yourself a fully-functioning LNMP server, so you’re good to go if that’s all you wanted. If you’re a WordPress user, this is where things get interesting, because the biggest single difference on the user-end between Nginx and Apache is the fact that .htaccess files mean nothing once you cross over.
So, getting on with it, have your server grab the latest WordPress release. We’ll keep using example.com for this.
user1@ve:/etc$ cd /var/www/example.com/public
user1@ve:/var/www/example.com/public$ rm index.html
user1@ve:/var/www/example.com/public$ wget http://wordpress.org/latest.tar.gz
user1@ve:/var/www/example.com/public$ tar -xzvf latest.tar.gz
user1@ve:/var/www/example.com/public$ sudo cp -rvf latest/* .
user1@ve:/var/www/example.com/public$ sudo rm latest.tar.gz
user1@ve:/var/www/example.com/public$ sudo rm -rvf latest
Now we’ll make example.com’s Nginx vhost file WordPress-ready.
user1@ve:/var/www/example.com/public$ sudo nano /etc/nginx/sites-available/example.com
Use the example below to set up your vhost file, note the changes from the original.
server {
listen 80;
server_name www.example.com;
rewrite ^/(.*) http://example.com/$1 permanent;
}
server {
listen 80;
server_name example.com;
access_log /var/www/example.com/logs/access.log;
error_log /var/www/example.com/logs/error.log;
root /var/www/example.com/public;
index index.php;
location / {
try_files $uri $uri/ @wordpress /index.php?q=$request_uri;
}
location @wordpress {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /var/www/example.com/public/index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_NAME /index.php;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
try_files $uri @wordpress;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/example.com/public$fastcgi_script_name;
include fastcgi_params;
}
}
Notice we changed the root index from index.html to index.php, and that new location blocks have been added to direct Nginx to look for requested resources through WordPress.
Restart Nginx to make the changes take effect.
user1@ve:/var/www/example.com/public$ sudo /etc/init.d/nginx restart
At this point, you could go ahead and install WordPress normally using the “famous” 5-minute install, but we’re going to go through it here with a couple of slight changes for security’s sake.
First thing’s first, fix all the permissions for the stuff you just unpacked in your site’s directory, then go to your WordPress site’s public directory and find wp-config-sample.php so we can make a usable copy of it. Then edit the file.
user1@ve:/var/www/example.com/public$ sudo chown -R www-data:www-data /var/www/example.com/public
user1@ve:/var/www/example.com/public$ sudo chmod -R 775 /var/www/example.com/public
user1@ve:/var/www/example.com/public$ cp wp-config-sample.php wp-config.php
user1@ve:/var/www/example.com/public$ nano wp-config.php
We need to fill in the values of the section labeled MySQL settings first. We’ll go through it chunk by chunk:
You can choose anything you wish for the blog’s database name, so long as it’s not wordpress, blog, wp, or press.
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'mydbase');
Again, you can choose anything you want for the blog’s database username, just not wordpress, blog, wp, or press.
/** MySQL database username */
define('DB_USER', 'dbaseuser');
Choose a strong password for your blog’s database user.
/** MySQL database password */
define('DB_PASSWORD', 'strongpass');
Since we’re working with a VPS here, this should be localhost. If it’s something funky, you should know and be able to look it up at your provider’s control panel.
/** MySQL hostname */
define('DB_HOST', 'localhost');
Go ahead and fill in utf8 here if it isn’t already.
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
Now scroll down the page to the line that reads “$table_prefix” — we want to change this to nearly anything but wp_, which is the absolute last thing you want the table prefix to be. Substitute “rawr” for anything you like.
/**
* WordPress Database Table prefix.
*
* You can have multiple installations in one database if you give each a unique
* prefix. Only numbers, letters, and underscores please!
*/
$table_prefix = 'rawr_';
Now that the wp-config.php file is ready to go, we’ll set up the MySQL database and user to match the info you gave it. Since we went to the trouble of installing phpMyAdmin, we’ll put it to good use right now. Go ahead and load php.example.com in your browser and log in using your database root login.
As soon as you’re logged in, you should see the field for “create new database” — go ahead and enter the word you used for the DB_NAME value in the config file.
Next, click the little “home” icon in the upper-left of your screen to go back to the main phpMyAdmin screen, and then click on the “Privileges” tab along the top. Once that loads, click “Add a new User.” Give the user the same username you used for the DB_USER value in the config file. For the “Host” field, use the dropdown menu and choose “Local.” Give the user the same password that you used for the DB_PASSWORD value in the config file (and repeat it). Don’t use the “Generate Password” button or field at all. Once they’re filled out, click the “Go” button down in the lower right.
Now go back to the “Privileges” tab again. Find the new user you just made and click the small “Edit Privileges” icon to the right of it, in the “Action” column. When the next page loads, look to the middle of the screen for the section labeled Database-specific privileges, and choose the new database from the dropdown menu. Hit “Check All” on the next page, then “Go.”
Now your wp-config.php matches what you have in your MySQL database, and we can finish installing WordPress. Go to http://example.com/wp-admin/install.php and fill in the info as you see fit.
While not nearly as necessary for security as obscure database values, there is an option to move your WordPress installation into a subdirectory, while still keeping the site itself at the root URL. Use these instructions if you want to take the extra step.
Now, there’s just one last thing to do to WordPress to make it fully functional with Nginx. Go to your plugins section of the Admin control panel and click “Add New.” In the search box, type “Nginx Compatibility” and search available plugins. The very first one to pop up, by Vladimir Kolesnikov, is the one you want. Click “Install Now,” then go back to your regular plugins page. If you want to upload the plugin yourself, grab it here first. Activate “nginx Compatibility (PHP5)” and leave the (PHP4) version deactivated. You can now use any permalink structure you want for your WordPress blog, because we’ve already set up the vhost file to handle the server-side redirects.
That’s it!
3 Responses:
Check this out. Slicehost’s articles section has a ton of shit. And they’ve been doing the whole VPS thing for a lot longer than MT. They rock.
http://articles.slicehost.com/
I like the Parallels Virtuozzo in play at MT, and static pricing more than variable (if you get random bot traffic, you pay for it with variable).
Otherwise, I hear nothing but good things about Slicehost’s VPS. Linode seems to be the cheapy on the block, but they have a good support section too.