The Road to Elysium

April 28, 2009

Fedora and SSHFS

Filed under: Linux — jorge @ 11:22

I had heard about sshfs before, but didn’t attempt anything with it til today. And I find it pure genius. A little about sshfs:

This is a filesystem client based on the SSH File Transfer Protocol. Since most SSH servers already support this protocol it is very easy to set up: i.e. on the server side there’s nothing to do. On the client side mounting the filesystem is as easy as logging into the server with ssh.

The idea of sshfs was taken from the SSHFS filesystem distributed with LUFS, which I found very useful. There were some limitations of that codebase, so I rewrote it. Features of this implementation are:

  • Based on FUSE (the best userspace filesystem framework for linux ;-)
  • Multithreading: more than one request can be on it’s way to the server
  • Allowing large reads (max 64k)
  • Caching directory contents

After having aquired my new VPS, I wanted to mount something over NFS to my workstation at home. Being that the VPS is running on OpenVZ, it doesn’t allow for normal NFS to work. I tried something called unfs3 instead, a user-space NFS-server. I ended up inventing new curse words yet again. So someone tipped me about sshfs, and it’s working like a dream. Mounting things is as easy as logging on to a remote system with regular ssh.

First install sshfs:

# yum install fuse-sshfs

In some cases, after having installed fuse-sshfs, you will have to add the user to the group fuse. If that’s the case, you can do so like this:

# gpasswd -a YourUserName fuse

Once you are in the group, you need to log out and in again for it to take effect. When logged in, you can mount things along the lines of:

$ sshfs user@server.example.com:/home/user/files /home/user/files

And that’s that! The only thing you have to worry about is that the folder you’re trying to mount on the remote machine has the same owner on your workstation. So the user jorge can pretty much mount anything on his workstation, from the remote machine, as long as it is owned by him.

To unmount something you can use:

$ fusermount -u /here/it/goes/

Enjoy!

April 23, 2009

nginx, PHP, MySQL and WordPress

Filed under: Linux — jorge @ 02:55

So, my machine at home took the plunge. A couple of days ago while I was reorganising the livingroom (I was not bored, I actually love doing that stuff), I placed the server on the floor, as it usually was placed above the TV. Michael then decided to play a little ON/OFF-game with the server. The powersupply was fried, and I can’t really bother to buy a new one at this moment. So, it was finally time for me to buy a VPS from out there somewhere. My decision fell on http://www.webhosting.uk.com, and they actually seem pretty good so far, so now to see if it will last.

My concern was though, VPS‘ (Virtual Private Server) aren’t usually that good, they have limited diskspace and hardware. I don’t need much of diskspace, but after some experience with Apache, I know it’s a huge memory-hog. So what I basically needed was Apache, MySQL, PHP and WordPress. I didn’t think it was going to work out, until a nice co-worker of mine tipped me off about nginx.

This was supposedly a very good, and very lightweight webserver, according to him. So I decided to give it a shot. And so far, it’s working wonders.

Here I’ll try to explain how to set up your server with nginx, MySQL, PHP and WordPress.

FastCGI

FastCGI is what your webserver uses to interact with PHP-code, and this is not something that comes packaged with nginx.

There are two options you can use, and I have tested both. spawn-fcgi or php-fpm. I ended up using php-fpm, though spawn-fcgi is quicker to set up. I’ll try to explain how to set up both.

spawn-fcgi

spawn-fcgi, which came with the webserver lighttpd. You usually had to download lighttpd first, compile it, and then grab the program from there. But for your convenience, you can get the spawn-fcgi here, or just go to http://redmine.lighttpd.net/projects/spawn-fcgi, and grab the source there to compile on your own (seems to be an own project now).

So basically, as root, do the following:

# wget http://jorge.fbarr.net/files/spawn-fcgi
# mv spawn-fcgi /usr/local/bin

Now, the next step is to make this program run at boot. For those of you using a RedHat’ish type of system, adding this to the end of /etc/rc.d/rc.local will do the trick. You can add it by running this command:

# echo '/usr/local/bin/spawn-fcgi -f /usr/bin/php-cgi -a 127.0.0.1 -p 9000 -P /var/run/fastcgi-php.pid -u nginx -g nginx' >> /etc/rc.d/rc.local

php-cgi is the name of the fcgi-application, which is usually provided by your distribution’s PHP-package (I believe it’s php-common for CentOS/Fedora, so make sure you have it installed), and is referred to by the -f in the command. -a makes you specify which address to listen on, -p is the port (9000 in this case), and -P is the file to place the process ID in when the program is started, which makes it easier to kill the program if necessary.

Once placed in the rc.local-file, just run it manually to fire it up:

# /usr/local/bin/spawn-fcgi -f /usr/bin/php-cgi -a 127.0.0.1 -p 9000 -P /var/run/fastcgi-php.pid -u nginx -g nginx

php-fpm

php-fpm is a patch for php4/5 to greatly improve FastCGI SAPI usage in production. This means that you don’t install php through your distribution’s package manager, but rather download the package from the PHP-website, and the patch from another site. You patch up the sourcecode, compile things, and get it started.

One of the dependencies for how we’re going to compile PHP is MySQL, so install that first by typing:

# yum install mysql mysql-devel

Then get the PHP-sourcecode by typing:

# cd /usr/local/src
# wget http://no2.php.net/get/php-5.3.0.tar.bz2/from/no.php.net/mirror

And the patch itself:

# wget http://php-fpm.org/downloads/php-5.3.0-fpm-0.5.12.diff.gz

Then execute the following command:

# tar -jxvf php-5.3.0.tar.bz2

Now we patch the newly downloaded PHP:

# gzip -cd php-5.3.0-fpm-0.5.12.diff.gz | patch -d php-5.3.0 -p1

And enter the new directory to start compiling things:

# cd php-5.3.0/
# ./configure --enable-fpm --with-mcrypt --enable-mbstring --with-mysql=/usr/include/mysql --with-mysql-sock=/tmp/mysql.sock --with-curl --enable-sockets --with-gd --with-zlib --with-iconv --with-jpeg-dir=/usr/lib

Notice: If you are using a 64-bit system you have to add in an –with-libdir=64 for it to compile correctly.
According to Raja Varma you need to use –with-libdir=lib64 for it to compile properly in a CentOS 64 bit installation. Thanks for the tip Raja!

At this point the compile failed quite a bit, as I had to install several more packages. The packages I had to install were the following (a snippet taken from yum.log):

Apr 23 08:34:44 Installed: zlib-devel-1.2.3-3.i386
Apr 23 08:34:50 Installed: libxml2-devel-2.6.26-2.1.2.7.i386
Apr 23 08:37:10 Installed: keyutils-libs-devel-1.2-1.el5.i386
Apr 23 08:37:18 Installed: libsepol-devel-1.15.2-1.el5.i386
Apr 23 08:37:23 Installed: libselinux-devel-1.33.4-5.1.el5.i386
Apr 23 08:37:30 Installed: e2fsprogs-devel-1.39-20.el5.i386
Apr 23 08:37:35 Installed: libidn-devel-0.6.5-1.1.i386
Apr 23 08:37:40 Installed: krb5-devel-1.6.1-31.el5_3.3.i386
Apr 23 08:37:46 Installed: openssl-devel-0.9.8e-7.el5.i386
Apr 23 08:38:07 Installed: curl-devel-7.15.5-2.1.el5_3.4.i386
Apr 23 08:40:15 Installed: libjpeg-devel-6b-37.i386
Apr 23 08:41:54 Installed: 2:libpng-devel-1.2.10-7.1.el5_3.2.i386
Apr 23 08:43:38 Installed: libmcrypt-2.5.8-4.el5.centos.i386
Apr 23 08:44:37 Installed: libmcrypt-devel-2.5.8-4.el5.centos.i386

Once everything compiles successfully, we continue with:

# make all
# make install

Now that everything is ready to go, we only need to modify two lines in the file /usr/local/etc/php-fpm.conf. Simply replace nobody with nginx, and remove the comments, making the lines look like this:

            Unix user of processes
            <value name="user">nginx</value>               
 
            Unix group of processes
            <value name="group">nginx</value>

And that should be it. Fire up php-fpm with:

# /usr/local/bin/php-cgi --fpm

Making an init-script for php-fpm is pretty easy – simply make a symlink that points to /usr/local/php/sbin/php-fpm:

# cd /etc/rc.d/init.d
# ln -s /usr/local/sbin/php-fpm php-fpm

Now add the following line to /etc/rc.d/rc.local to make php-fpm start up at boot:

/usr/local/sbin/php-fpm

And you’re done!

Now to the next item on the list, nginx.

nginx

nginx (pronounced as “engine X”) is a lightweight, high performance web server/reverse proxy and e-mail (IMAP/POP3) proxy HTTP server and mail proxy server written by Igor Sysoev.

So based on that we’re using CentOS now, we are going to get the necessary package from the EPEL-repository. Run these commands to fetch the package, and to install it:

# wget http://download.fedora.redhat.com/pub/epel/testing/5/i386/nginx-0.6.38-1.el5.i386.rpm
# yum --nogpgcheck localinstall nginx-0.6.38-1.el5.i386.rpm

Once installed, we need to configure three files, mainly. /etc/nginx/fastcgi_params, /etc/nginx/nginx.conf and /etc/nginx/conf.d/virtual.conf (if you want to have several virtual domains). The first file, fastcgi_params, we just need to add a little something. Open up the file and add the following line to it, right under SCRIPT_NAME:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;

Save and close the file.

This is what my nginx.conf pretty much looks like:
Notice: According to http://delicious.com/trash123/nginx:

...do not use the given nginx,conf, it is malicious point your server to his site.

Let me just say again, this is what MY configuration file looks like. I’ve simply pasted it so that you can see how a working configuration looks. So if you want it to work for you, you need to modify the values to suit your setup. I thought that was needless to say, but guess not. :)

#######################################################################
#
# This is the main Nginx configuration file.  
#
# More information about the configuration options is available on 
#   * the English wiki - http://wiki.codemongers.com/Main
#   * the Russian documentation - http://sysoev.ru/nginx/
#
#######################################################################
 
#----------------------------------------------------------------------
# Main Module - directives that cover basic functionality
#
#   http://wiki.codemongers.com/NginxMainModule
#
#----------------------------------------------------------------------
 
user              nginx;
worker_processes  1;
 
error_log         /var/log/nginx/error.log;
#error_log        /var/log/nginx/error.log  notice;
#error_log        /var/log/nginx/error.log  info;
 
pid               /var/run/nginx.pid;
 
 
 
#----------------------------------------------------------------------
# Events Module 
#
#   http://wiki.codemongers.com/NginxEventsModule
#
#----------------------------------------------------------------------
 
events {
    worker_connections  1024;
}
 
 
#----------------------------------------------------------------------
# HTTP Core Module
#
#   http://wiki.codemongers.com/NginxHttpCoreModule 
#
#----------------------------------------------------------------------
 
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
 
    log_format  main  '$remote_addr - $remote_user [$time_local] $request '
                      '"$status" $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
 
    access_log  /var/log/nginx/access.log  main;
 
    sendfile        on;
    #tcp_nopush     on;
 
    #keepalive_timeout  0;
    keepalive_timeout  65;
 
    proxy_read_timeout 300;
 
    #gzip  on;
 
    # Load config files from the /etc/nginx/conf.d directory
    include /etc/nginx/conf.d/*.conf;
 
    #
    # The default server
    #
    server {
        listen       80;
        server_name  chihiro.fbarr.net;
 
        #charset koi8-r;
 
        #access_log  logs/host.access.log  main;
 
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
 
        error_page  404              /404.html;
        location = /404.html {
            root   /usr/share/nginx/html;
        }
 
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
 
        # proxy the PHP scripts to Apache listening on 127.0.0.1:20080
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}
 
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    include        fastcgi_params;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        #}
 
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
}

The only thing I’ve changed here is server_name, which I’ve set to chihiro.fbarr.net. This is like the main server we’re working with. Now I’m going to want to set up the virtual host jorge.fbarr.net on this machine as well. For that we need to configure the file /etc/nginx/conf.d/virtual.conf. This is what mine looks like:

#
# A virtual host using mix of IP-, name-, and port-based configuration
#
 
 
## jorge.fbarr.net
server {
    listen       80;
    server_name  jorge.fbarr.net;
 
    port_in_redirect off;
 
    root   /var/www/jorge.fbarr.net;
 
    proxy_redirect     off;
    proxy_redirect     http://jorge.fbarr.net:80/  /;
 
    access_log /var/log/nginx/jorge.fbarr.net-access.log;
    error_log  /var/log/nginx/jorge.fbarr.net-error.log;
 
    include /etc/nginx/fastcgi_params;
 
    index   index.php;
 
    if (!-e $request_filename) {
        rewrite ^(.+)$ /index.php?q=$1 last;
    }
 
    location ~ .*\.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
    }
}
 
 
## jorge.ulver.no redirect
 
server {
    listen      80;
    server_name jorge.ulver.no;
 
    rewrite ^(.*) http://jorge.fbarr.net$1 permanent;
}

That’s pretty much it. Everything should be working just fine by now. :) But we are lacking two things, MySQL and WordPress.

MySQL and WordPress

To install MySQL, type up the following:

# yum install mysql-server

As for how to set up MySQL, if you follow these instructions, it will tell you how you need to set up your database to work with WordPress, so I won’t be posting details about that here.

For PHP to be able to work with MySQL (if you have chosen to use spawn-fcgi and not php-fpm), you need to install a package called php-mysql. Install the package with yum, kill php-cgi, and start it again by doing these following things:

# yum install php-mysql
# pgrep php-cgi | xargs kill
# /usr/bin/spawn-fcgi -f /usr/bin/php-cgi -a 127.0.0.1 -p 9000 -P /var/run/fastcgi-php.pid -u nginx -g nginx

Once everything is done, voila! You should now have nginx, PHP, MySQL and WordPress working together. And as you probably notice, nginx is taking a LOT less resources than Apache would have.

Issues with PHP

If you notice that errors such as the following are popping up on your site:

It is not safe to rely on the system's
timezone settings. Please use the date.timezone setting, the TZ
environment variable or the date_default_timezone_set() function.

You can do the following:

cp /usr/local/src/php-5.3.0/php.ini-production /usr/local/lib/

Then open up the file php.ini and change:

;date.timezone =

to

date.timezone = "Europe/Oslo"

If you happen to live in Oslo. Change it to whatever is right for you really. Also, find the line that says something like:

error_reporting = E_ALL & ~E_NOTICE

And change it to:

error_reporting = E_ALL & ~E_DEPRECATED

Restart php-fpm and nginx and things should be back to normal.

Enjoy!

Powered by WordPress