Wednesday, June 9, 2010

Fun with nginx, upstart, and lucid

Howdy boys and girls!

Today we'll be mangling us some web.

I've started off by installing a fresh copy of Ubuntu Lucid Server in Virtualbox 3.2.4. Mind, if you're using a Linux host, turn *ON* host caching in the "SATA Controller" if your host's using EXT4 as the filesystem your VDIs are stored on, otherwise it will try to use AIO and corrupt your VDIs. The host kernel needs a patch to fix this, but neither karmic or lucid have it, apparently. Anyway.

The Core System

For my first act, I've shuttled over my SSH public keys so I can use my agent to login.

ssh kamilion@laptop # Say no or ^C to make empty ~/.ssh dir with proper perms!
scp kamilion@laptop:/home/kamilion/.ssh/authorized_keys ~/.ssh/authorized_keys
tee -a /etc/ssh/sshd_config <<-\EOA

# No passwords! Get bent, crackers!
PasswordAuthentication no
EOA

For my second act, I've tossed a couple of the more useful utilities on. (python-software-properties gives you "add-apt-repository ppa:freenx-team" shortcuts)

sudo apt-get install python-software-properties dnsutils openssh-server denyhosts screen htop rsync nethogs sqlite3

Make *sure* you add your REAL origin IPs to /etc/hosts.allow

tee -a /etc/hosts.allow <<-\EOA

sshd: 10.0.0.5
sshd: 24.48.64.128
EOA
AND edit /etc/denyhosts.conf to enable blocklist sync.

nano /etc/denyhosts

At the bottom, you need to uncomment: SYNC_SERVER, SYNC_DOWNLOAD, SYNC_DOWNLOAD_THRESHOLD = 10, and SYNC_DOWNLOAD_RESILIENCY = 2d
then:
/etc/init.d/denyhosts restart

This will sync the ssh blocklists from the denyhosts server.
Uncomment SYNC_UPLOAD too, please contribute your stats!

(Yes, I know this is pointless after shutting off password auth, but BETTER SAFE THAN SORRY.)

Virtual Machines

If you're using a VM, this might be handy:

sudo apt-get install build-essential dkms
sudo rm /etc/init/tty[2-6].conf  #Disable other TTYs because this is a VM.

The virtualbox guest additions will use dkms to build the guest kernel modules automatically.

You can select the Install Guest Additions from the vbox menu to insert the ISO into the cdrom.

/media/cdrom/autorun.sh

The Webserver

Now we'll install nginx.

sudo apt-get install nginx

And set it up to startup on boot with upstart.
The prestart tests the config; handy!

sudo tee /etc/init/nginx.conf <<-\EOA
# /etc/init/nginx.conf
# nginx - starts the nginx webserver

description "nginx"

start on (net-device-up and local-filesystems)
stop on runlevel [016]

pre-start exec /usr/sbin/nginx -t

expect fork
respawn
exec /usr/sbin/nginx
EOA


Now you should be able to

start nginx

and check port 80 for the default "Welcome to nginx!" response.

Right -- so this is served out of /var/www/ by default and controlled from /etc/nginx/ in such a manner that you dump config stanzas into a file in /etc/nginx/sites-available/ and link them as such:

sudo ln -s /etc/nginx/sites-available/fqdn.com /etc/nginx/sites-enabled/fqdn.com && sudo service nginx reload

you should get a working vhost with a proper config.

So, we're now capable of serving static pages, what else can we do?

Let's check which modules and defaults our nginx was compiled with:

nginx -V

nginx version: nginx/0.7.65
TLS SNI support enabled
configure arguments: --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/body --http-proxy-temp-path=/var/lib/nginx/proxy --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --with-debug --with-http_stub_status_module --with-http_flv_module --with-http_ssl_module --with-http_dav_module --with-http_gzip_static_module --with-http_realip_module --with-mail --with-mail_ssl_module --with-ipv6 --add-module=/build/buildd/nginx-0.7.65/modules/nginx-upstream-fair

Looks like we've got fastcgi, DAV, FLV streaming, gzip and mail-proxy by default.

Installing PHP5

Now for PHP5.

sudo apt-get install php5-cgi php5-mysql php5-pgsql php5-sqlite php5-suhosin php5-imap php5-mcrypt php5-gd # php5-gd is usually needed

# security disclosure risk: shut php up -- hide version!
sudo sed -i '/expose_php/s/\;exp/exp/;/expose_php/s/=.*/= 0/' /etc/php5/cgi/php.ini
grep 'expose_php' /etc/php5/cgi/php.ini

sudo tee /etc/init/php-fastcgi.conf <<-\EOA
# /etc/init/php-fastcgi.conf
# php-fastcgi - starts php-cgi as an external FASTCGI process

description "php-fastcgi - respawning UNIX Socket"

start on (net-device-up and local-filesystems)
stop on runlevel [!2345]

expect fork
respawn
exec /usr/bin/sudo -u www-data PHP_FCGI_CHILDREN=5 PHP_FCGI_MAX_REQUESTS=125 /usr/bin/php-cgi -q -b /tmp/php-fastcgi.socket
EOA

Okay, now to start it.

start php-fastcgi

PHP5 FastCGI for nginx

Now you'll need an nginx config.

Here's one of my templates:

# Enable with
# sudo ln -s /etc/nginx/sites-available/fqdn.com /etc/nginx/sites-enabled/fqdn.com && sudo service nginx reload

server {
        listen                  80;
        server_name             fqdn.com www.fqdn.com;
        access_log              /var/www/fqdn.com/log/access.log;
        error_log               /var/www/fqdn.com/log/error.log;

        location / {
                root            /var/www/fqdn.com/public/;
                index           index.php index.html;
                }

        location ~ \.php$ {
                fastcgi_pass    unix:/tmp/php-fastcgi.socket;
                fastcgi_index   index.php;
                fastcgi_param   SCRIPT_FILENAME /var/www/fqdn.com/public$fastcgi_script_name;
                include         fastcgi_params;
                }
        }

### Redirect www to root domain?
#server {
#       listen                  80;
#       server_name             www.fqdn.com;
#       rewrite                 ^/(.*) http://fqdn.com/$1 permanent;
#       }

### Redirect root domain to www?
#server {
#       listen                  80;
#       server_name             fqdn.com;
#       rewrite                 ^/(.*) http://www.fqdn.com/$1 permanent;
#       }

### HTTPS server
#server {
#       listen                  443;
#       server_name             fqdn.com;
#       ssl                     on;
#       ssl_certificate         /var/www/fqdn.com/private/cert.pem;
#       ssl_certificate_key     /var/www/fqdn.com/private/cert.key;
#       ssl_session_timeout     5m;
#       ssl_protocols           SSLv2 SSLv3 TLSv1;
#       ssl_ciphers             ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
#       ssl_prefer_server_ciphers       on;
#       access_log              /var/www/fqdn.com/log/secure.access.log;
#       error_log               /var/www/fqdn.com/log/secure.error.log;
#       location / {
#               root            /var/www/fqdn.com/public/;
#               index           index.php index.html;
#               }
#       location ~ \.php$ {
#               fastcgi_pass    unix:/tmp/php-fastcgi.socket;
#               fastcgi_index   index.php;
#               fastcgi_param   SCRIPT_FILENAME /var/www/fqdn.com/public$fastcgi_script_name;
#               include         fastcgi_params;
#               }
#       }



The Database

Okay, let's move on and install a real database. Doesn't really matter which you choose. I'm gonna go with mysql for now so we can use phpmyadmin later.

sudo apt-get install mysql-server

Enter your new mysql root password twice.



Now for phpmyadmin.

sudo apt-get install phpmyadmin

It'll ask which server you want to configure it for -- leave both apache2 and lighttpd disabled and continue. Yes, we want to use dbconfig-common. Enter your mysql root password for the first one; then just hit enter to have phpmyadmin generate it's own account and random password.

sudo tee /etc/nginx/sites-available/phpmyadmin <<-\EOA
# Enable with
# sudo ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/phpmyadmin && sudo service nginx reload
server {
        listen 80 default;
        server_name localhost;
        access_log /var/www/apps/logs/phpmyadmin.access.log;
        error_log /var/www/apps/logs/phpmyadmin.error.log;

        location / {
            root /usr/share/phpmyadmin;
            index index.php;
            }

        location ~ \.php$ {
            include /etc/nginx/fastcgi_params;
            fastcgi_pass unix:/tmp/php-fastcgi.socket; #127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin$fastcgi_script_name;
            }
        location /nginx_status {
            # copied from http://blog.kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/
            stub_status on;
            access_log   off;
            allow 24.48.64.128; # Home
            allow 10.0.0.5; # Work
            deny all;
            }

        }
EOA

Make some empty logdirs or nginx will go splat when it can't access them.

mkdir -p /var/www/apps/logs/
chown -R www-data.www-data /var/www/apps/logs/

Kill the pesky default site now that we have phpmyadmin. (yes, "reload nginx" is a command. Nifty, huh? The magic of Upstart!)

ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/phpmyadmin
rm  /etc/nginx/sites-enabled/default
reload nginx


You should now be able to access phpmyadmin and login with root/mysqlpass.
phpmyadmin also can synchronize two mysql instances now, as well.


Additional Information and Tricks

SSH tunnels are your friend! Sync DBs over ssh with phpmyadmin!
ssh -vg -L 8080:localhost:80 -R 33306:mysql-server.home:3306 user@fqdn.com

firefox http://localhost:8080/server_synchronize.php

replace mysql-server.home with whatever hostname/ip has the mysqld instance you wish to sync with. You can pick any port instead of 33306, just make sure you tell phpmyadmin to look at "localhost" on that port.

You can clone whole servers too!
push.sh:
#/bin/bash
rsync -azvv -e ssh /var/www/ root@fqdn.com:/var/www/
rsync -azvv -e ssh /etc/nginx/ root@fqdn.com:/etc/nginx/


pull.sh:
#!/bin/bash
rsync -azvv -e ssh root@fqdn.com:/etc/nginx/ /etc/nginx/
rsync -azvv -e ssh root@fqdn.com:/var/www/ /var/www/



Want a remote mini-desktop? This'll take a couple minutes.
add-apt-repository ppa:freenx-team
apt-get install freenx-server firefox gnome-core synaptic

Boom, grab the nxclient.

Now, go forth and serve pages!

No comments: