I have shared a web site with a photographer friend of mine for several years. I would like to do some other, more modern things, with my web server so it’s time to upgrade. I have been using RedHat as my Linux distribution for …. well since RedHat version 4 or 5. But when I started using Vagrant VMs when I looked for RH Virtual Box images, the CentOS or Fedora images where generally much larger than the Ubuntu images. So I started playing with Ubuntu. And at work we are planning to use Ubuntu for our new project because we want something that supports AppArmor - so means Arch or something in the Debian family. Ubuntu is widely used in the Rails and Django communities so seems like a good choice. The latest long-term supoort version is Ubuntu 14.04, aka Trusty.
Having chosen my Linux distribution, I need to chose a hosting service. The two current contenders for low cost VPS’s are DigitalOcean and Linode. A couple of years ago Linode sponsored RailsRumble and provided the hosting for all the contestants. It seemed fairly decent and had some nice options like their StackScripts. So I think I’ll use Linode.
New Linode Server
I spun up a Linode 2G instance on Ubuntu 14.04 LTS with a 512 Mb swap disk (max it would allow me to set). That same form asked me to set a root password for the new server.
Using that password, I logged in and immediately did:
apt-get update
apt-get upgrade
apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev \
sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
useradd -g staff -m -s /bin/bash cnk
useradd -g staff -m -s /bin/bash tim
# and set passwords for both of us
apt-get install emacs24-nox
# added both tim and cnk to the sudoer's file
From the Getting Started Guide
hostname
One of the first things the Getting Started guide asks you to do is to set the hostname.
root@localhost:/# echo "trickster" > /etc/hostname
root@localhost:/# hostname -F /etc/hostname
Edited /etc/hosts to add one line mapping the public IP assigned to me to the hostname I just configured. The final file is:
127.0.0.1 localhost
127.0.1.1 ubuntu
45.79.nnn.nnn trickster.<domain>.org trickster
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Time zone
The default for Ubuntu is for servers to use UTC until that is changed to something else:
root@localhost:~# date
Wed Jun 17 06:04:31 UTC 2015
root@localhost:~# dpkg-reconfigure tzdata
..... I get a 'GUI' that let's me choose my timezone
Current default time zone: 'US/Pacific'
Local time is now: Tue Jun 16 23:05:07 PDT 2015.
Universal Time is now: Wed Jun 17 06:05:07 UTC 2015.
Securing the server
Linode also has an excellent security guide so let’s work through that.
sshd Configuration
It suggests disabling password authentication and only allowing keys. OK so I copied my public key into the ~/.ssh/authorized_keys file on the linode box. So I can now ssh without a password.
Then I edited /etc/ssh/sshd_config to disable password authentication and root login and restarted sshd.
Setting Up iptables
The guide has a fairly sensible looking set of firewall rules for IP tables and good instructions for how to create them in a file and then load them into iptables. The defaults look just fine to me for now so I just followed the instructions. And similarly I followed the instructions for how to get loading the firewall rules into the boot sequence before the network interface is enabled. I would need to reboot the server to see if that really worked but don’t feel like it just now.
The guide also suggested setting up Fail2Ban but since we are not allowing logins with passwords, I am not really sure how helpful that is. We do have ZenPhoto set up to password protect most of our albums, mostly because we were getting comment spam on the old version of the site. So perhaps I will want to set that up at some point - but not for now.
Installing MySQL, Apache, and PHP
Linode also has a guide for setting up a LAMP stack on their server (including some tuning for their smallest (1G RAM) offering). But I had found this other guide for setting up Rails on Ubuntu 14.04, so I mostly used it.
Installing and Configuring MySQL
So first, install some packages:
sudo apt-get install mysql-server mysql-client libmysqlclient-dev
For reference, this gives me mysqld Ver 5.5.43-0ubuntu0.14.04.1 for debian-linux-gnu on x86_64 ((Ubuntu))
I was prompted to set a root password for the database which I
did. The default install bound MySQLd to 127.0.0.1:3306 which is good
and the default_storage_engine is InnoDB - also good. But the default
server character set is latin1. It is the 21st century and I think we
should all be using UTF8 all the time. So I created a file in /etc/mysql/conf.d/default_charset_utf8.cnf
and used what I had used yesterday when I set up MySQL a CentOS system
with MySQL 5.5:
[mysqld]
default-character-set = utf8
But the server would not restart. In the error log I see:
/usr/sbin/mysqld: unknown variable 'default-character-set=utf8'
Hun? Searching for that error message turned up this blog post
which claims that option was deprecated in MySQL 5.0. Searching the
MySQL docs, I only see default-character-set
as a command line
option. Apparently the more correct way to do this now is:
[mysqld]
character_set_server = utf8
That works:
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
Checking the security of my MySQL server set up, there do not appear
to be any test databases or anonymous access to the database. And root
can only log in locally. While I was in the mysql console, I created
the zenphoto
user and zenphoto_prod
database.
Apache, PHP, and ZenPhoto
A week or so ago, I had installed LAMP + the new version of ZenPhoto on a VM (using Vagrant) so I could see how feasible it would be to migrate directly from our super old ZenPhoto to the latest version by creating database migration files. So now I need to do the same thing on the new server. First I installed apache and PHP:
apt-get install apache2 libapache2-mod-php5 php5-mysqlnd php5-gd
I was able to use the defaults for most of the apache configuration. I
may want to use the status command. In /etc/apache2/envvars
file
there is the following comment:
## The command to get the status for 'apache2ctl status'.
## Some packages providing 'www-browser' need '--dump' instead of '-dump'.
# export APACHE_LYNX='www-browser -dump'
Looks like w3m satisfies that requirement so I changed the line above
to export APACHE_LYNX='w3m -dump'
I now see the default Apache page for Ubuntu when I go to the IP
address of my server. I didn’t make any changes to the php
parameters. Later, I may need to tweak the parameters in /etc/php5/apache2/php.ini
but for now I am just going to move on to installing ZenPhoto.
ZenPhoto
I copied zenphoto-zenphoto-1.4.7.tar.gz up to the server, untarred it
into /var/www/html/
and renamed the folder to just ‘zenphoto’.
chown -R www-data:www-data zenphoto
ZenPhoto supplies an example config file:
zp-core/zenphoto_cfg.txt
. You copy that to
zp-data/zenphoto.cfg.php
and then edit it to provide the
database connection information, etc.
chmod 600 zp-data/zenphoto.cfg.php
Normally what one would do next is navigate to the zenphoto/zp-core/setup.php url and let the set up script install everything. But I want to use the data from our current site. Fortunately zenphoto is set up so people can share a database by setting a tablename prefix. So by setting the table prefix for the new site to something different than our original install, I was able to have complete sets of tables for the old and new installations in the same database. I went through the tables field by field and found that although there were some new columns, I was able to write SQL statements to copy info from the original site into the new tables. The admin / configuration information was very different so I did not attempt to tranfer that. But the image and album information was very similar so it was pretty straightfoward to transfer most of the data into the new schema.
Once I had the original album and image data in the new tables, I
navigated to http://<ipaddress>/zenphoto/
to run the setup script on
top of the mostly set up database. With the database in place and the
software set up, I used rsync to transfer the photos into the albums
directory on the new site.
Rewrite rules for pretty urls
Now I can navigate to the photo albums - but the urls are
different. The old site was using rewrite rules to create pretty urls
like: http://ictinike.org/zenphoto/tim/misc/ted_09/
but the new
site is serving that alubum page as
http://45.79.100.71/zenphoto/index.php?album=tim/misc/ted_09
The install script had asked if I wanted it to create a .htaccess file
and I had said yes. mod_rewrite was not enabled by default in my
apache install but I had enabled it using sudo a2enmod rewrite
but still no dice. The .htaccess files from the old and new versions
of ZenPhoto are very different so it was hard to tell if that was the
issue, or something else. In fact the new file says:
# htaccess file version 1.4.5;
# Rewrite rules are now handled by PHP code
# See the file "zenphoto-rewrite.txt" for the actual rules
#
# These rules redirect everything not directly accessing a file to the
# Zenphoto index.php script
...
In the ZenPhoto admin interface there is a checkbox under URL options
for mod rewrite
. When I check that, the links in the pages are
now the ‘pretty urls’ that I expect. But clicking on them gives me a
404 error. Unchecking the box gives me back the index.php + query args
urls - which work. Hmmmmm. It took me a while to figure out that the
issue was that my main apache configration was set to ignore .htaccess
files. In my /etch/apache2/apache2.conf
:
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
I could have allowed .htaccess files to be used by changing the AllowOverride directive. But since I have full control over the configs, it seemed more sensible to just copy the rules from the .htaccess file into the virtual host config file for my ZenPhoto site. Since ZenPhoto does a lot of magical set up, I didn’t remove the unused .htaccess file from the zenphoto directory - in case something in the ZenPhoto admin checks to see if it is available.
<Directory />
# CNK copied this from the .htaccess file in /zenphoto
# rather than change the AllowOverride settings globally
#
# htaccess file version 1.4.5;
# Rewrite rules are now handled by PHP code
# See the file "zenphoto-rewrite.txt" for the actual rules
#
# These rules redirect everything not directly accessing a file to the Zenphoto index.php script
#
<IfModule mod_autoindex.c>
IndexIgnore *
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /zenphoto
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [L]
RewriteRule ^.*/?$ index.php [L,QSA]
</IfModule>
</Directory>
Comment configuration
OK almost everything is up and running. But I don’t see the comments I migrated - nor do I see a comment form on each page. I didn’t transfer the configuration stuff via the database, so I need to enable comments from the admin interface There is a configuration page for the comments plugin - asking if we need people’s names and email addresses and whether or not to allow anonymous or private commenting. I am going to defer to Tim on how he wants that set up. I did go ahead and enable one of the captcha plugins so at least there is a small barrier to comment spam. That and the comment system will email us about new comments - once I get email set up. See the next post for how I set up an outgoing mail server on the new machine. With that working, all I had to do was enable the zenphoto_sendmail plugin to get new comments emailing us. I think that just sends mail as if it were using /usr/bin/sendmail (which postfix will pick up as a backwards compatibility nicety). If we want something more configurable, we may want to switch to the PHPMailer plugin which allows you to set more configuration options in the ZenPhoto admin interface.
Search
There is an archive page that shows when all the photos were taken (based on the EXIF data I think). The listings were there but the pages it linked to said “no images found”. But when I clicked the “Refresh Metadata” button on the main admin page, it rebuilt whatever index was needed to make the images show up on the by date listings.