Archive for the ‘Programming’ Category

Odd Thing About Symlinks

Friday, May 20th, 2016

I refactored a site recently and rather than having a bunch of files with identical headers and footers, I created an index.php file with conditionals to create the meta data and then include the content. To preserve the existing file structure, I just created symlinks to the index.php file. So I did something like this:

ln -s index.php oldname1.php
ln -s index.php oldname2.php

This works great and is pretty easy to implement. (Yes there are other ways to do it.)

I ran into a problem when I tried to create symlinks in some subdirectories to prevent the “You don't have permission to access /include.php/ on this server.” error message. I turns out that you have to be in the subdirectory where you want the alias to reside. This works:
cd Guides
ln -s ../manuals/index.php index.php

This does not:

cd manuals
ln -s index.php Guides/index.php

Is the server alive?

Friday, January 29th, 2016

I’ve been working on a server that has been going offline. I can tell it’s offline because I get an indicator in my mail program that shows that I can’t get mail. The first time it happened we called over to the data center and had them restart everything. That worked for a while but then it happened again. This time we went over to the data center and the server itself was fine. Replacing the switch that connected two servers made the problem go away. A few weeks later, the server went offline again. This time it looked like it was a DDOS. It has been fine ever since, but we wanted to have a better way of knowing that there is an issue than me happening to look at my email program and noticing that I wasn’t getting mail.

One way to see if it is alive is to ping the server every few minutes. If I get no response, then send a text to the owner and an email to me.

I have a couple of cron job on my server running under my crontab that send out notifications by text or email every minute. So I edited the crontab to add another job to its list.

To see the cron jobs, crontab -l -u myuserid. To edit type, crontab -e.

# m h  dom mon dow   command
*/1 * * * * /home/myuserid/
*/1 * * * * /home/myuserid/

Here’s the shell script I wrote to ping the server and send out notifications.

ping -c 1  -q  1>/dev/null 2>&1;

if [ $return_code -ne 0 ]; then
    #echo "Failure";
    mail -s "Server Down" < /dev/null

I ping it once (-c 1), quietly—since I don’t care about the result (-q) and send the result and any error messages to /dev/null. All I care about is whether it was successful. Every Linux command has an exit status code. You can access it with $?. I only care if the command ran successfully, so I check to see if it is not 0.

I don’t need any details in the text that I send, so I set the subject and grab the content from

Spinning up a new Virtual Machine

Thursday, June 25th, 2015

Most of my websites are low volume and so I host them on the same VPS at Linode. For a new project, I decided to put the websites on a separate VPS. I spent a day researching the current choices and you probably won’t go wrong with any of them. For me, it came down to either Linode (which I’ve been happy with) or Digital Ocean (which I’ve used for backups and helping my nephew learn programming). Since I don’t need a lot of space right now and I had a referral code, I decided to go with the $5/mo Digital Ocean plan.

Since I’m familiar with it, I installed Ubuntu 14.04.2 LTS with Apache, MySQL, and PHP. I have some customizations that I made to make it consistent with my current server.

Users, Permissions, and Groups

The first thing I did was log in as root and create a new user—me and add myself to the sudoer’s table.

   adduser myusername

There are a couple of ways to do this but for now I just added my user name directly instead of creating a sudoers group like I normally do.

    myusername ALL=(ALL:ALL) ALL

Without logging out of the root account, I logged in with my username and edited the /etc/ssh/sshd_config. This was a test to see whether I could log in as myself and that I could edit files owned by root using sudo. I then changed PermitRootLogin to no

    # Authentication:
    PermitRootLogin no

To get the chances to take effect, I restarted the SSH daemon with sudo service ssh restart.

I like to have a group that is able to edit all of the files in www. I call this different things on different machines, e.g. ‘staff’, ‘web-admin’, ‘www’. On this machine I’m using ‘www’.

If you type the command groups, you can see which groups you belong to. To add a new group you can edit the groups file or use these commands to add a group and add a member to a group.

    sudo groupadd www
    sudo usermod -a -G www myusername


I don’t know how they find random IP addresses to attach, but 7 minutes after installing Fail2ban it banned the first site. Installation is straightforward. I didn’t make any customizations except to add my IP address and change the email address for notifications.

    sudo apt-get install fail2ban
    sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
    sudo vi /etc/fail2ban/jail.local
    sudo service fail2ban restart
    sudo iptables -L

Updating Apache

First, I updated my .profile as I described in an earlier post. Then I changed the default location for my web pages from /var/www/html to /srv/www. First I created a www directory in srv. Then made a symlink to it in root.

I want everyone in the web admin group to be able to edit the files so I ran sudo chown myusername:www www

I edited the /etc/apache2/apache2.conf file to change the default location to /www and prevent directory listing—I removed Indexes from Options.

    <Directory /www/*>
        Options FollowSymLinks
        AllowOverride None
        Require all granted

I don’t want people to see the contents of my .inc files. Some people add the suffix .pho to them to hide them, but I prefer to make them all invisible to browsers.

# We don't want people to see .inc files
<Files  ~ "\.inc$">
  Order allow,deny
  Deny from all

I also don’t want people to see the Subversion files from my WordPress installs.

Order deny,allow
Deny from all

And I don’t want anyone to see .git files, although best practice says don’t put them in document root.

Order deny,allow
Deny from all

Since I don’t have a domain name attached to this IP address, I added these lines to the bottom of the conf file.

    # Suppress the warning message when restarting Apache until we get a FQDN
    ServerName localhost

I have a couple of templates for websites so I put one in the www directory for testing. Then I changed the DocumentRoot in 000-default.conf to that directory and restarted Apache.


I don’t plan to use a database for these websites, but I do need to at least set up MySQL and PhpMyAdmin. I followed the instructions at Digital Ocean to change the root password and add myself as a user.

phpMyAdmin install is straightforward, except that you need to add this line:

Include /etc/phpmyadmin/apache.conf

to the end of your /etc/apache2/apache2.conf and restart Apache—even if you are running the latest version of Ubuntu LTS.

Then I installed git using the command sudo apt-get install git-core.

Finally, I need to convert MySQL databases to SQLite databases for use in Apple Apps so I installed SQLite.

    apt-get install php5-sqlite
    sudo apt-get install sqlite3

Things I can’t remember – Git

Saturday, June 7th, 2014

In git you clone a project—not checkout like in Subversion. You’ll probably want to put it in a directory that has a name that is the same as the project (or related to the project name).

$ git clone git:// importantProject

If you are hosting your own git server, you’ll probably use something like this.

$ git clone importantProject

Once you’ve cloned the repository you’ll have the exact same files and file structure as the original. You’ll also be in the master branch.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working directory clean

You’ll also get a .git directory with the following files.

$ cd .git
total 28
-rw-r--r--   1 username  staff    23B Jun  2 09:31 HEAD
drwxr-xr-x   2 username  staff    68B Jun  2 09:31 branches/
-rw-r--r--   1 username  staff   312B Jun  2 09:31 config
-rw-r--r--   1 username  staff    73B Jun  2 09:31 description
drwxr-xr-x  11 username  staff   374B Jun  2 09:31 hooks/
-rw-r--r--   1 username  staff   8.8K Jun  2 09:34 index
drwxr-xr-x   3 username  staff   102B Jun  2 09:31 info/
drwxr-xr-x   4 username  staff   136B Jun  2 09:31 logs/
drwxr-xr-x   4 username  staff   136B Jun  2 09:31 objects/
-rw-r--r--   1 username  staff   107B Jun  2 09:31 packed-refs
drwxr-xr-x   5 username  staff   170B Jun  2 09:31 refs/

Now suppose I modify my robots.txt file.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   robots.txt

no changes added to commit (use "git add" and/or "git commit -a")

$ git diff
diff --git a/robots.txt b/robots.txt
index 90098a4..3aa5532 100755
--- a/robots.txt
+++ b/robots.txt
@@ -1,3 +1,5 @@
 # robots.txt for

 User-agent: *
+Disallow: /order/

Before we commit the file, we need to stage it. The status command above tells you how to to it.

$ git add robots.txt

We can see the staged changes with:

$ git diff --staged
diff --git a/robots.txt b/robots.txt
index 3aa5532..abd2889 100755
--- a/robots.txt
+++ b/robots.txt
@@ -3,3 +3,4 @@
 User-agent: *
+Disallow: /order/

Now $git diff returns nothing because there are no unstaged changes.

We can add and commit it in one command.

git commit -a
[master 4623ad2] Added a disallow
 1 file changed, 2 insertions(+)

Alternatively, you can combine the commit with the message.

git commit -a -m "Added a disallow"
[master 4623ad2] Added a disallow
 1 file changed, 2 insertions(+)

You can remove files from the repository by deleting them from your work area. They will show up in the unstaged area or you git status output. You can also use git rm to remove a file.

Likewise you can rename a file with mv originalName newName and git will notice. Or you can use git mv originalName newName.

You can view the commits that you have made with git log.

$ git log
commit 4623ad2cbe4163e2d013c7e53728023e4d7163e6
Author: User Name < >
Date:   Tue Jun 3 07:55:00 2014 -0700

    Added a disallow

commit 065b7362f9ad19d6e2fe69cde9629abf0beabb95
Author: User Name < >
Date:   Mon Feb 24 09:00:03 2014 -0800

    Changed site name and added blank line at end of files

commit 61277e4d12636044e9b873608c325470d98577e0
Author: User Name < >
Date:   Mon Feb 24 07:50:56 2014 -0800

    Started tracking changes to site with git.

If you want to see the changes that were made as well, use the -p option (patch option) and the output will be piped into a pager where you can page through all the changes. Hit ‘q’ to quit the pager.

You can browse the commit messages with the –pretty option.

$git log --pretty=oneline
4623ad2cbe4163e2d013c7e53728023e4d7163e6 Added a disallow
065b7362f9ad19d6e2fe69cde9629abf0beabb95 Changed site name and added blank line at end of files
61277e4d12636044e9b873608c325470d98577e0 Started tracking changes to site with git.

Once you have identified the commit you want more info on you can display the info with git show and the first few digits of the hash. Usually five digits is enough to uniquely identify the commit, but you can use all of them if you want.

$ git show --format=raw 4623a
commit 4623ad2cbe4163e2d013c7e53728023e4d7163e6
tree 9c73a1afbfb9ec4930d3d4ac8d906e6ae4683df6
parent 065b7362f9ad19d6e2fe69cde9629abf0beabb95
author User Name <> 1401807300 -0700
committer User Name <> 1401807300 -0700

    Commit message

diff --git a/robots.txt b/robots.txt
index 90098a4..3aa5532 100755
--- a/robots.txt
+++ b/robots.txt
@@ -1,3 +1,5 @@
 # robots.txt for

 User-agent: *
+Disallow: /order/

Often you might be looking for the last time a particular file was changed. –name-only gives the name of the file, the commit message, and the hash.

$ git log --name-only
commit 4623ad2cbe4163e2d013c7e53728023e4d7163e6
Author: Gordon Miller <developer@well.golly>
Date:   Tue Jun 3 07:55:00 2014 -0700

    Added a disallow


commit 065b7362f9ad19d6e2fe69cde9629abf0beabb95
Author: jscarry <>
Date:   Mon Feb 24 09:00:03 2014 -0800

    Started tracking changes to site with git.


Things I can’t remember—bless

Saturday, February 2nd, 2013

When making .dmg’s or CDs I often want a folder to be open when the .dmg or CD is opened. To do this you use this command.

bless --folder /Volumes/FolderName/ --openfolder /Volumes/FolderName/

Well Golly

Atheism Plus

Buy from Amazon