Category Archives: Linux

BASH conditional expressions

-a file

True if file exists.

-b file

True if file exists and is a block special file.

-c file

True if file exists and is a character special file.

-d file

True if file exists and is a directory.

-e file

True if file exists.

-f file

True if file exists and is a regular file.

-g file

True if file exists and its set-group-id bit is set.

-h file

True if file exists and is a symbolic link.

-k file

True if file exists and its “sticky” bit is set.

-p file

True if file exists and is a named pipe (FIFO).

-r file

True if file exists and is readable.

-s file

True if file exists and has a size greater than zero.

-t fd

True if file descriptor fd is open and refers to a terminal.

-u file

True if file exists and its set-user-id bit is set.

-w file

True if file exists and is writable.

-x file

True if file exists and is executable.

-G file

True if file exists and is owned by the effective group id.

-L file

True if file exists and is a symbolic link.

-N file

True if file exists and has been modified since it was last read.

-O file

True if file exists and is owned by the effective user id.

-S file

True if file exists and is a socket.

file1 -ef file2

True if file1 and file2 refer to the same device and inode numbers.

file1 -nt file2

True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.

file1 -ot file2

True if file1 is older than file2, or if file2 exists and file1 does not.

-o optname

True if the shell option optname is enabled. The list of options appears in the description of the -o option to the set builtin (see The Set Builtin).

-v varname

True if the shell variable varname is set (has been assigned a value).

-R varname

True if the shell variable varname is set and is a name reference.

-z string

True if the length of string is zero.

-n stringstring

True if the length of string is non-zero.

string1 == string2string1 = string2

True if the strings are equal. When used with the [[ command, this performs pattern matching as described above (see Conditional Constructs).

=’ should be used with the test command for POSIX conformance.

string1 != string2

True if the strings are not equal.

string1 < string2

True if string1 sorts before string2 lexicographically.

string1 > string2

True if string1 sorts after string2 lexicographically.

arg1 OP arg2

OP is one of ‘-eq’, ‘-ne’, ‘-lt’, ‘-le’, ‘-gt’, or ‘-ge’. These arithmetic binary operators return true if arg1 is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to arg2, respectively.  Arg1 and arg2 may be positive or negative integers.

 

 

Source http://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html

Create an encrypted LUKS sparse file

For an updated version of this article, check this post!

I’m going to create a 2.7TB of file (sparse file) on my 3TB disk.
This file is a ‘thin provisionig‘ file, which means that it will expand only when/if used. FYI – it won’t shrink after usage. So a 2.7TB sparse file, once created, will be seen as 2.7T but it’s actually using a very little space (almost not noticeable). It will grow using it.
I will also encrypt it using cryptosetup LUKS format, to protect the content.

Why a sparse file?
Well, it’s practical, and it’s very handy if you want to move your files from a disk which is quite full already. In fact, I have my backups on this USB drive, EXT4 formatted. A 3TB drive half full.
A sparse file can be actually bigger than the available space on the disk. Of course, if you fill it up, it will error out. But while you want to move files, it’s… your saviour! 🙂

Using my example, I have 1.2TB used on this 3TB disk. I want to move all this data in an encrypted container that can potentially use the whole disk. So? Sparse file is the solution!
Theoretically I could also have had like… 2.2/2.5TB of data (on a 2.7TB available disk). As long as you free up space moving the files, things should work 🙂

First of all… if you haven’t done it yet, just install the package:

# apt-get install cryptsetup

Create the sparsefile

Let’s create a 2.7TB sparse file in /3TB.
[/3TB is the mount point of my /dev/sdb1 USB device]

# dd of=/3TB/file_container.img bs=1 count=0 seek=2700G

Create an encrypted LUKS container

We mount the sparse file just created and set the encrypted password. NOTE: you can change/add/remove this password (key) [later on explained how 😉 ]

# losetup /dev/loop0 /3TB/file_container.img 
# cryptsetup -y luksFormat /dev/loop0 
WARNING! ======== This will overwrite data on /dev/loop0 irrevocably. 
Are you sure? (Type uppercase yes): YES 
Enter passphrase: 
Verify passphrase: 
#

Open the Vault

Now, it’s time to ‘turn on’ this encrypted volume device and check that all went well

# cryptsetup luksOpen /dev/loop0 myarchive
Enter passphrase for /3TB/file_container.img:

# cryptsetup status myarchive
/dev/mapper/myarchive is active.
type: LUKS1
cipher: aes-xts-plain64
keysize: 256 bits
device: /dev/loop0
loop: /file_container.img
offset: 4096 sectors
size: 5662306304 sectors
mode: read/write

And of course, we need to format the device. I’ll use EXT4.

# mkfs.ext4 -L cryptarchive /dev/mapper/myarchive
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 707788288 4k blocks and 176947200 inodes
[...]
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

At this point, you can mount this device /dev/mapper/myarchive as usual:

# mkdir /cryptoarchive
# mount -t ext4 /dev/mapper/myarchive /cryptoarchive

You are now able to use your encrypted sparse file! All files can be now copied/moved into/cryptoarchive

Close the Vault

To unmount the vault, you need to follow these steps. This is important when you turn off your server!

# umount /cryptoarchive
# cryptsetup luksClose /dev/mapper/myarchive
# losetup -d /dev/loop0

Add key to the container

LUKS allows for up to 8 passwords to each partition/vault.
You can add other 7 basically and use all of these 8 passwords to access your vault.

To add keys, vault needs to be ‘open’

# losetup /dev/loop0 /3TB/file_container.img
# cryptsetup luksOpen /dev/loop0 myarchive
# cryptsetup luksAddKey /dev/loop0
< enter any current phrase - and add new phrase >

Change the key of the container

To change the key, the vault/container needs to be ‘close’

# cryptsetup luksClose /dev/mapper/myarchive
# cryptsetup luksChangeKey /dev/mapper/myarchive 
< verify and change your passphrase here>

Setup auto mount

This will generate a new file as a key, added to the vault and set to be used to auto mount at boot:

# dd if=/dev/urandom of=/root/keyfile bs=1024 count=4
# chmod 0400 /root/keyfile
# cryptsetup luksAddKey /dev/loop0 /root/keyfile
Enter any passphrase:
~#

Than we need to setup /etc/crypttab and /etc/fstab

# cat /etc/crypttab
# <target name>	<source device>		<key file>	<options>
myarchive /dev/loop0 /root/keyfile luks

# tail -n1 /etc/fstab
/dev/mapper/myarchive /cryptoarchive ext4 defaults,noauto 0 2

After that, I have personally created a specific init script. I couldn’t find the right way to run losetup /dev/loop0 /3TB/file_container.img before activating the archive, so…
First of all, I’ve disables cryptdisks via /etc/default/cryptdisks

CRYPTDISKS_ENABLE=No

Than, I’ve created this init script, saved as /etc/init.d/crypt-myvault

#! /bin/sh
### BEGIN INIT INFO
# Provides:          crypt-myvault
# Required-Start:    $remote_fs $syslog mountall netatalk
# Required-Stop:     $remote_fs $syslog mountall netatalk
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Manage encrypted vault
# Description:
### END INIT INFO

CONFFILE=/etc/default/crypt-myvault

. $CONFFILE > /dev/null 2>&1

if [ -z ${SPARSEFILE} ] || [ -z ${VAULT} ]; then
    echo "Required parameters missing.
	  Please configure $CONFFILE

	  # Example #
	  ENABLE=true
	  SPARSEFILE=/<path>/<file.img>
	  VAULT=<vault_name>
          "
    exit 1
fi


if [ ! $ENABLE ]; then
   echo "$0 disabled in $CONFFILE. Please set ENABLE=true and retry"
   exit 1
fi

checkconfig () {
if grep -q "^/dev/mapper/$VAULT" /etc/fstab && grep -q "^$VAULT" /etc/crypttab ; then
    CHK=0
else
    CHK=1
    echo "$VAULT doesn't seem configured in /etc/fstab or /etc/crypttab.\nUnble to continue."
fi
}

mount_myarchive () {
 /sbin/losetup /dev/loop0 $SPARSEFILE
 /sbin/cryptdisks_start $VAULT
 /bin/mount /dev/mapper/$VAULT
}

umount_myarchive () {
 /bin/umount /dev/mapper/$VAULT
 /sbin/cryptdisks_stop $VAULT
 /sbin/losetup -d /dev/loop0
}



case "$1" in
    start)
        echo "Enabling and mounting $VAULT"
	checkconfig
        mount_myarchive
        ;;
    stop)
        echo "Umounting and disabling $VAULT"
	checkconfig
        umount_myarchive
        ;;
    check)
	checkconfig
	[ $CHK -eq 0 ] && echo "Check OK" || echo "Check FAILED"
	;;
    *)
        echo "Usage: $0 start|stop|check"
        exit 1
        ;;
esac

exit 0

This script requires also a /etc/defaults/crypt-myvault configuration file:

# Conf file for /etc/init.d/crypt-myvault
ENABLE=true
SPARSEFILE=/3TB/file_container.img
VAULT=myarchive
VAULT_MOUNT_POINT=/cryptoarchive

To finish, we need to enable the script:

# update-rc.d crypt-myvault defaults

We need to be sure that this script runs AFTER the USB drive is mounted. So… I’ve added ‘netatalk’ as required-start in the header of the init script, as I’ve noticed that once netatalk starts, the USB disk is already mounted.
I’m sure there is a better/nicer way, but this seems to work well for me 🙂

Sources:

http://serverfault.com/questions/696554/creating-a-grow-on-demand-encrypted-volume-with-luks

LUKS passphrases: Changing, adding, removing

https://www.howtoforge.com/automatically-unlock-luks-encrypted-drives-with-a-keyfile

Dynamic MOTD on Debian

Here a simple script that setup a dynamic MOTD message ‘ubuntu-like’ on Debian servers:

#!/bin/bash

# Script to install Dynamic MOTD on Debian servers

# This version uses figlet

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root or using sudo"
   exit 1
fi

if [ ! -f /etc/debian_version ] ; then
   echo "This script can run ONLY on Debian OS"
   exit 1
fi

# Install required packages:
# - figlet: ASCII art for hostname
# - lsb-release: get distro details (fallback)
apt-get install figlet lsb-release

# Backup MOTD file
mv -f /etc/motd{,.ORIG}

# Symlink dynamic MOTD file
ln -s /var/run/motd /etc/motd

# Create dynamic motd environment
mkdir /etc/update-motd.d/
cd /etc/update-motd.d/

cat <<'EOF' > 00-header
#!/bin/sh
#
#    00-header - create the header of the MOTD
#
[ -r /etc/os-release ] && . /etc/os-release
OS=$PRETTY_NAME

if [ -z "$OS" ] && [ -x /usr/bin/lsb_release ]; then
        OS=$(lsb_release -s -d)
fi

figlet -f slant $(hostname)
printf "\n"
printf "\t- %s\n\t- OS version %s\n\t- Kernel %s\n" "$OS" "$(cat /etc/debian_version)" "$(uname -r)"
printf "\n"
EOF

cat <<'EOF' > 10-sysinfo
#!/bin/bash
#
#    10-sysinfo - generate the system information
#
date=`date`
load=`cat /proc/loadavg | awk '{print $1}'`
root_usage=`df -h / | awk '/\// {print $(NF-1)}'`
home_usage=`df -h /home | awk '/\// {print $(NF-1)}'`
memory_usage=`free -m | awk 'NR==2{printf "%.2f%%\n", $3*100/$2 }'`
swap_usage=`free -m | awk '/Swap/ { printf("%3.1f%%", "exit !$2;$3/$2*100") }'`
users=`users | wc -w`
time=`uptime | grep -ohe 'up .*' | sed 's/,/\ hours/g' | awk '{ printf $2" "$3 }'`
processes=`ps aux | wc -l`
ip=`ifconfig $(route -n | grep '^0.0.0.0' | awk '{ print $8 }') | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'`


printf "System information as of %s\n\n" "$date"
printf "IP Address:\t%s\tSystem uptime:\t%s\n" "$ip" "$time"
printf "System load:\t%s\tProcesses:\t%s\n" "$load" "$processes"
printf "RAM used:\t%s\tSwap used:\t%s\n" "$memory_usage" "$swap_usage"
printf "Usage on /:\t%s\tUsage on /home:\t%s\n" "$root_usage" "$home_usage"
printf "Local Users:\t%s\tProcesses:\t%s\n" "$users" "$processes"
EOF


cat <<'EOF' > 90-footer
#!/bin/sh
#
#    90-footer - write the admin's footer to the MOTD
#
[ -f /etc/motd.tail ] && cat /etc/motd.tail || true
EOF


chmod +x /etc/update-motd.d/*

clear
echo "Installation completed. Please logout and login again to test."

 

If you are running CentOS7, here the how to for that OS.

Backup – rsnapshot and rdiff (multiple backups)

This is a very basic/simple guide about how to setup incremental and versioned backups of your Linux computers and Mac. 🙂

Initial problem:

    • Time Machine is unreliable after a while, and when you put on sleep your Mac, most of the time it complains because the USB drive wasn’t disconnected properly :@
    • I’d like to be able to have an incremental/versioning backup system local BUT also have some of critical files uploaded in the cloud [using some cron and some cloud provider’s utility]
    • Time Machine on external drives uses ‘sparsebundle’ storage system, which is complicated to open and extract files from Linux command line [I’ve previously created a Time Machine on the pi, and I was thinking to create a sort of system to open the sparsebundle file, and upload the files during the night – but this doesn’t seem easy or neither really reliable]
    • Backing up VMs with Time Machine takes ages, as if a little bit changes, the whole content gets copied over (space and time consuming)

So… I needed something that could:

  • Do incremental backups storing only the differences (for VMs) to avoid to transfer every time GBs of data for little changes
  • Do versioning of small files (documents, videos, music, etc…) based on a custom schedule
  • Be accessible on the filesystem without tricky stuffs (like opening a ‘sparsebundle’ file
  • Be able to run on a raspberry pi and mostly likely, able to access Linux and Mac systems, and have a centralised backup system.

Answer: combination of rsnapshot and rdiff-backups… plus some sort of Cloud Provider’s utility to sync part of this content on the Cloud (still work in progress).
I found this nice article where it explains the differences between the two tools, and it should clarify why I’ve chosen to use a combination of both of them and not just one.
The main bit is this one:

rdiff-backup stores previous versions as compressed deltas to the current version similar to a version control system. rsnapshot uses actual files and hardlinks to save space. For small files, storage size is similar. For large files that change often, such as logfiles, databases, etc., rdiff-backup requires significantly less space for a given number of versions.

So, I’ve installed rsnapshot and rdiff-backups on my pi. Packages are available using apt-get command.
After that, I have created one rsnapshot configuration file for each of my linux machines (actually pi’s) and one for my Macrdiff-backup will be called within rsnapshot, in a post-exec script (option available, and very handy).

It’s clearly necessary to have SSH enable on your Linux and Mac machines. Also, in this particular case, I have added the following in visudo on the Mac, to allow the user to run pmset passwordless:

user ALL=(ALL) NOPASSWD: /usr/bin/pmset

Configuration files

I’m posting 2 configuration examples: one for my pi (local backup_, and the other onefor my Mac (remote backup – via ssh/rsync).
I’ve literally kept the original /etc/rsnapshot.conf just as reference – not actively using at all.

Here my custom configuration files:

/etc/default/rsnapshot

This is a file that I’ve created and I use it as “default/general” parameters that I include in any of the other custom files. Why? Just to avoid to copy and paste the same on any custom file 🙂

#####################################
# Default configuration paramenters #
#####################################
# just use include_conf <tab> file:
#include_conf /etc/default/rsnapshot
config_version 1.2
no_create_root 1
cmd_cp /bin/cp
cmd_rm /bin/rm
cmd_rsync /usr/bin/rsync
cmd_ssh /usr/bin/ssh
cmd_logger /usr/bin/logger
cmd_du /usr/bin/du
du_args -csh
link_dest 1
use_lazy_deletes 1
rsync_numtries 3
#stop_on_stale_lockfile 0

PI configuration file (local backup)

pi1_rsnap.conf

# pi1 conf file
include_conf /etc/default/rsnapshot
snapshot_root /USB/backups/pi1/
#retain hourly 6
retain daily 7
retain weekly 4
retain monthly 12
logfile /var/log/rsnapshot/p1.log
lockfile /USB/backups/rsnapshot_run/pi1.pid
#sync_first 1
verbose 2
loglevel 5
use_lazy_deletes 1
backup /home/ files/
backup /etc/ files/
backup /var/spool/cron/ files/
backup_script /usr/bin/dpkg --get-selections > packages.txt installed-packages/

This script copies home, etc, cron into /USB/backups/pi1/daily.0/files/.
The last line also execute the command and pull the output file and store within /USB/backups/pi1/daily.0/installed-packages/


The MAC configuration (remote backup).

This requires some extras.
What I’ve done is combining a pre and post script around the rsnapshot backup, in order to obtain the following:

  1. waking up the MAC via wake-on-lan package (this is possible because my MAC is connected also via ethernet)
  2. connect via ssh
  3. send a command to keep the disk on and avoid them to go in idle
  4. visually notify that the backup is about to run (in case someone is currently using the Mac)
  5. run the rsnapshot backup
  6. once finished, run rdiff-backup for the big files (VMs)
  7. once done, kill the process that was keeping the disks on
  8. visual notification sent to inform that backup has completed
  9. disconnect. If no one is connected, the Mac will go back in standby (if enabled).
  10. clean up old rdiff-backups

mac_rsnap.conf

# mac conf file
include_conf /etc/default/rsnapshot
snapshot_root /USB/backups/mac/
#retain hourly 6
#retain daily 7
retain weekly 4
retain monthly 12
logfile /var/log/rsnapshot/mac.log
lockfile /USB/backups/rsnapshot_run/mac.pid

#rsync_short_args -a
rsync_long_args --delete --numeric-ids --relative --delete-excluded --filter=". /etc/rsnapshot_configs/mac/<span style="color: #0000ff;">rsync_selections</span>"

#sync_first 1
verbose 1
loglevel 5
use_lazy_deletes 1

# Specify the path to a script (and any optional arguments) to run right
# before rsnapshot syncs files
<span style="color: #339966;">cmd_preexec</span> /etc/rsnapshot_configs/mac/<span style="color: #0000ff;">pre-exec.sh</span>

# Specify the path to a script (and any optional arguments) to run right
# after rsnapshot syncs files
<span style="color: #339966;">cmd_postexec</span> /etc/rsnapshot_configs/mac/<span style="color: #0000ff;">rdiff_vms.sh</span>

#Remote backup
</code><code>backup user@mac:/ files/

The following bash scripts have some parameters that need to be set manually (highlighted in orange)

pre-exec.sh

#!/bin/bash

# --------------------------------------------- #
# This script wake up the mac box via ethernet
# using wake-on-lan, wait for ssh connection,
# connects and issue a command to keep the
# disks on for the following backup tasks.
#
# There is a timeout for number of tries. If
# reached, an email notification will be sent.
# --------------------------------------------- #

# Email parameters
EMAIL="<span style="color: #ff9900;">[email protected]</span>"
SENDMAIL=<span style="color: #ff9900;">/usr/sbin/sendmail</span>

# MAC details
MACADDR="<span style="color: #ff9900;">xx:xx:xx:xx:xx:xx</span>"
USER=<span style="color: #ff9900;">user</span>
HOST=<span style="color: #ff9900;">mac</span>

# Estimated amount of time to get ssh available
waitBeforeTry=<span style="color: #ff9900;">40</span>

# Retries parameters
sleepSecInterval=5
maxConnectionAttempts=10

# --------------------------------------------- #
emailnotification () {
echo -e "Subject:$1\n" | $SENDMAIL $EMAIL
logger "${BASH_SOURCE[0]} PID $ - $1"
}

# Turn on your mac via Ethernet LAN
sudo /usr/sbin/etherwake $MACADDR

sleep $waitBeforeTry

index=1
while (( $index <= $maxConnectionAttempts ))
do
echo quit | telnet $HOST 22 2>/dev/null | grep -q Connected
if [ $? -ne 0 ] ; then
sleep $sleepSecInterval
((index+=1)) #; echo "DEBUG: $index"
else
break
fi
done

# Notify if reach max attempts
MSG="Unable to connect to $USER@$HOST after $maxConnectionAttempts attempts."
[ $index -eq $maxConnectionAttempts ] && emailnotification $MSG

# Connect via ssh and disable sleep and disksleep
ssh $USER@$HOST 'sudo pmset sleep 0'
ssh $USER@$HOST 'sudo pmset disksleep 0'
#ssh $USER@$HOST 'nohup pmset noidle > /dev/null 2>&1 &'
ssh $USER@$HOST ' osascript -e '"'"'display notification "Starting Backup in few seconds" with title "Backup starts" sound name "default" '"'"' '

sleep 5

rdiff_vms.sh

#!/bin/bash

# Script executed after rsnapshot
USER=<span style="color: #ff9900;">user</span>
HOST=<span style="color: #ff9900;">mac</span>

# ===================================================
rdiff-backup --exclude-symbolic-links $USER@$HOST::Users/user/Documents/VMs/ /USB/backups/mac/VMs/

# All files should be now backed up

# Re-setting previous values for sleep and disksleep... and notify
ssh $USER@$HOST 'sudo pmset sleep 10'
ssh $USER@$HOST 'sudo pmset disksleep 10'
#ssh $USER@$HOST 'pkill pmset noidle'
ssh $USER@$HOST ' osascript -e '"'"'display notification "Backup has now completed." with title "Backup Finished" sound name "default" '"'"' '

# Putting on sleep the box - NOT REQUIRED
# sleep will happen automatically and no risk to force sleep if I'm using it
#ssh $USER@$HOST 'sudo pmset sleepnow'

# Cleaning up old backups: remove backups older than 6 months
rdiff-backup --remove-older-than 6M --force /USB/backups/mac/VMs/

The following file is the one used as ‘filter‘ for rsync. It uses that syntax.
To clarify, this does the backup of Documents, Pictures, Movies, Music folders ONLY from the user called ‘user‘, excluding the subfolders ‘VMs‘ in Documents, all the folders that starts with ‘Season‘ in Movies, any other possible folders in ‘user’ home dir, and any file/folder starting with .Spotlight, .Trash and .DS_Store files in ANY subfolders.

rsync_selections

+ Users/
+ Users/user/
+ Users/user/Documents/
+ Users/user/Pictures/
+ Users/user/Movies/
+ Users/user/Music/
- .Spotlight*
- .Trash*
- .DS_Store
- Users/user/Documents/VMs/
- Users/user/Movies/Season*/
- Users/user/*
- Users/*
- /*

/etc/cron.d/rsnapshot
This is the CRON that executes the backup jobs.
The ‘less frequent’ job needs to run before the ‘most frequent’. I’ve explained this later in this post, however the reason is that the actual active sync happens JUST in the most frequent job, and the others are just rotations made with a ‘mv’ command. So, it’s important to make the rotation BEFORE the sync.

###############
# >>> MAC <<< #
###############
# set to run only weekly at 10:30 am on Monday
30 10 * * 1 user /usr/bin/rsnapshot -c /etc/rsnapshot_configs/mac/mac_rsnap.conf weekly
# Monthly rotation at 10:00 am (1st every month)
0 10 1 * * user /usr/bin/rsnapshot -c /etc/rsnapshot_configs/mac/mac_rsnap.conf monthly
###############
# >>> PI <<< #
###############
# Daily 9:30am
30 9 * * * root /usr/bin/rsnapshot -c /etc/rsnapshot_configs/pi_rsnap.conf daily
# Weekly 9:05am (Sunday)
5 9 * * 7 root /usr/bin/rsnapshot -c /etc/rsnapshot_configs/pi_rsnap.conf weekly
# Monthly 9:00am (1st every month)
0 9 1 * * root /usr/bin/rsnapshot -c /etc/rsnapshot_configs/pi_rsnap.conf monthly

Folders created:

/USB/                               [mount point of my external USB drive]
/USB/backups/                       [subfolder to keep all the backups]
/USB/backups/pi/                    [folder for 'pi' box]
/USB/backups/mac/                   [folder for 'mac']
/etc/rsnapshot_configs/             [where I keep all the conf files]
/var/log/rsnapshot/                 [log files - chmod 1777*]
/USB/backups/rsnapshot_run/         [dir for jobs' pids - chmod 1777*]

*Use chmod 1777 on logs and run folders if you want other users than root to run the backups and write log files.


Let’s clarify some bits and pieces

sync_first 1

To be sure to properly complete the first full backup, enable  sync_first setting this to 1. Once completed, remove/comment it out.
To execute the first sync, run the following:

rsnapshot -c my_rsnapshot.conf sync

Basically, run the sync as many times you want… and once you have finished, you will start invoking (with CRON) the daily, weekly, monthly… etc backups. REMEMBER to disable it once finished, otherwise you won’t actually run any sync!

TABs no spaces!

IMPORTANT: do NOT use spaces in the rsnapshot configuration files but only TABS!!!
Copy and paste might change tabs to spaces so be sure to review all your configs. Use the -t flag to test every time if syntax is correct.

Test your configuration (-t)

rsnapshot -t -c my_rsnapshot.conf <sync|daily|weekly... >

The -t will also display exactly the command that it’s going to be executed – very handy! 🙂

Remote backups

Another thing to keep in mind is that ‘REMOTE’ backups (whatever uses user@host …) are actually launching the command on the remote host so it’s required to have rsync installed on the remote machine too (and rdiff-backup if used too). Versions should also match. If not, at least rsync should be version >= 3.
To allow this to work on my Mac, for instance, I had to install “rdiff-backup” and install a newer version of “rsync”, as the default version is 2.6.x. I’ve used the Rudix packages. Easy easy 🙂

Retain daily/weekly/monthly… sync… wtf?!

Very important to understand about rsnapshot that made me kinda mad for few hours: the job that DOES the backup is the one on the top of the list (most frequent).
So, if you have daily, weekly, monthly… set as ‘retain’ parameters in the rsnapshot conf file, the one that does actually the copy of the files is ‘daily‘ (top of the list – most frequent). The other ones are JUST some sort of rotation of the folder tree. Literally a ‘mv’ command… that’s it. You can verify this using -t flag to see the commands.
So, don’t get confused 🙂

So, to summarise:

  • sync: first initial backup – handy especially to create the initial backup. This creates a .sync folder in snapshot_root.
  • daily: this is the one that does the copy (or the ‘most frequent’ backup set – in mac for example, I set that to be ‘weekly’ and ‘monthly’ only, so in that case, weekly is the most frequent backup set and it’s the one that does the sync
  • weekly/monthly… (less frequent backups): these are simply ‘mv’ commands.

To explain more in details… the flow of my Mac…
You run the first sync (as many times as you want), with ‘sync_first‘ enabled.

rsnapshot -c my_rsnapshot.conf sync

This creates the backup in /USB/backups/mac/.sync/
Than you run the crons. Weekly will be the first to run:

rsnapshot -c my_rsnapshot.conf weekly

This will actually run this move, creating the first weekly folder:

mv /USB/backups/mac/.sync/ /USB/backups/mac/weekly.0/

Than, DISABLE ‘sync_first’ and the next time the weekly cron will be executed, something like that will run, moving the weekly.0 to weekly.1, hard linking the identical files and sync’ing the ones that have been changed since:

mv /USB/backups/mac/weekly.0/ /USB/backups/mac/weekly.1/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded \
    --link-dest=/USB/backups/mac/weekly.1/files/ /home/ \
    /USB/backups/mac/weekly.0/files/
[...]

Then, next time, weekly.2 and weekly.3 will be created: same method.
Until the LAST backup is created (#3, in this case -> 4 retention – from 0 to 3), the monthly job won’t take any affects.
Once we have /USB/backups/mac/weekly.3/, and this will be executed…

rsnapshot -c my_rsnapshot.conf monthly

… this will be executed:
mv /USB/backups/mac/weekly.3/ /USB/backups/mac/monthly.0/

And so and so…

Little note, keeping the above example. You might start this backup in the middle of month, so at the end of the month you won’t have reached the 4th weekly backup sets, but just the 2nd (#0 and #1). So.. what happens with the ‘monthly’ one that will run on the 1st of the month?
Answer: nothing.
Basically, this time the monthly backup will skip as the previous max retention limit is not reached yet. Weekly backups will continue rotating within themselves.
The first week of the second month, weekly backup will reach #2 (third backup). #1 => #2, #0 =>  #1 and the new backup stored in #0.
Second week #3 (4th and last). #2 => #3, #1 => #2, #0 =>  #1 and the new backup stored in #0. The #3 (oldest) should be the one that rotates… but the monthly cron won’t be executed until the next month. But there’s nothing to be worried about. Next weekly run, on the third week, the #3 will be marked for deletion, and a new #0 will be created.  Same for the forth week. Oldest backup deleted, max limit reached.
And here, we will get into the new month, where the monthly backup will be called BEFORE the weekly one, and it will rotate weekly.3 in monthly.0, and the weekly (#3 => monthly#0, #2 => #3, #1 => #2) freeing up ‘one space’ (#0). This will be filled up from the next ‘weekly’ run, and all will be ‘in sync’ for the next months. 🙂

I hope this example clarifies. 🙂

NOTE:
If you are decide, one day, to move your backup from one disk to another one, MAKE SURE to rsync preserving the hard links, otherwise your backup will raise like a cake in the oven! 🙂

Here a sample command:

rsync -az -H --delete --numeric-ids /path/to/source server2:/path/to/dest/

Banana Pi Pro – WLAN configuration

Add ‘ap6210‘ to /etc/modules to enable WiFi, and use modprobe ap6210 to force load the module.

Check dmesg to see if all has been loaded correctly. If not, reboot and check again.

dmesg|grep WLAN

Install the required packages:

apt-get install wireless-tools iw wpasupplicant

Modify /etc/network/interfaces

# Dinamic IP:
auto wlan0
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ap-scan 1
wpa-scan-ssid 1
wpa-ssid "WIFI_NETWORK_NAME"
wpa-psk "WLAN-KEY"

# Static IP:
auto wlan0
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.xx.yy
netmask 255.255.255.0
gateway 192.168.0.1
wpa-ap-scan 1
wpa-scan-ssid 1
wpa-ssid "WIFI_NETWORK_NAME"
wpa-psk "WLAN-KEY"

Bring the interface up:

ifconfig wlan0 up

Source: http://oyox.de/882-wlan-auf-bananian-banana-pi-einrichten/

Nagios3 and Lighttpd

This guide will explain how to install Nagios3 on a machine with Debian and Lighttpd webserver.

If you haven’t installed Lighttpd yet, please follow this tutorial.

Install Nagios server

Now, let’s install Nagios.

apt-get install nagios3 nagios-plugins nagios-nrpe-plugin

This will automatically install all the required dependencies.

Enable check_external_commands in /etc/nagios3/nagios.cfg

check_external_commands=1

Add www-data in nagios’ group:

usermod -a -G nagios www-data

And fix some permission issues to avoid some errors like “error: Could not stat() command file”

chmod g+x /var/lib/nagios3/rw

Let’s configure a bit Lighttpd.
Make sure cgi and php modules are enabled.

Then, create a new conf file and enable it:

vim /etc/lighttpd/conf-available/10-nagios3.conf
# Nagios3
 
alias.url =     (
                "/cgi-bin/nagios3" => "/usr/lib/cgi-bin/nagios3",
                "/nagios3/cgi-bin" => "/usr/lib/cgi-bin/nagios3",
                "/nagios3/stylesheets" => "/etc/nagios3/stylesheets",
                "/nagios3" => "/usr/share/nagios3/htdocs"
                )
 
$HTTP["url"] =~ "^/nagios3/cgi-bin" {
        cgi.assign = ( "" => "" )
}
 
$HTTP["url"] =~ "nagios" {
        auth.backend = "htpasswd"
        auth.backend.htpasswd.userfile = "/etc/nagios3/htpasswd.users"
        auth.require = ( "" => (
                "method" => "basic",
                "realm" => "nagios",
                "require" => "user=nagiosadmin"
                )
        )
        setenv.add-environment = ( "REMOTE_USER" => "user" )
}
lighttpd-enable-mod nagios3

Let’s apply the changes:

/etc/init.d/lighttpd force-reload

We need to setup the “nagiosadmin” password:

htpasswd -c /etc/nagios3/htpasswd.users nagiosadmin

Now, open your browser and digit http://yourserver/nagios3
Insert username: nagiosadmin and the password you’ve just chosen… and voila`… 🙂

And now we have installed our nagios server. As you can see, it’s currently monitoring itself.

But what about the other hosts in the network?

Adding hosts

Host configuration

To let our Nagios server to monitor other hosts, we need to follow these steps on any client we want to add:

apt-get install -y nagios-plugins nagios-nrpe-server

Once completed, we need to add the IP of our monitoring host in /etc/nagios/nrpe.cfg under allowed_hosts=xxx.xxx.xxx.xxx.

Also, add this line in /etc/nagios/nrpe_local.cfg:

command[check_all_disks]=/usr/lib/nagios/plugins/check_disk -w '20%' -c '10%' -e -A

This will be used from our monitor server to query nrpe and provide info about ALL the disks.
You can use also -I flag to exclude a specific path. For example on my Time Capsule Pi, I’ve used the following line, to exclude the mount point “TimeMachine” from the checks:

command[check_all_disks]=/usr/lib/nagios/plugins/check_disk -w '20%' -c '10%' -e -A -I '/TimeMachine/*

Monitoring configuration for new host

Now back to our Nagios monitoring machine
In /etc/nagios3/conf.d create a file called for example host1_nagios2.cfg and add the following basic services (add/remove/modify based on your local configuration):

define host{
        use             generic-host
        host_name       host1
        alias           host1
        address         xxx.xxx.xxx.xxx
}

define service{
        use                     generic-service
        host_name               host1
        service_description     Current Load
        check_command           check_nrpe_1arg!check_load
}

define service{
        use                     generic-service
        host_name               host1
        service_description     Current Users
        check_command           check_nrpe_1arg!check_users
}
define service{
        use                     generic-service
        host_name               host1
        service_description     Disk Space
        check_command           check_nrpe_1arg!check_all_disks
}
define service{
        use                     generic-service
        host_name               host1
        service_description     Total Processes
        check_command           check_nrpe_1arg!check_total_procs
}

Also, you can add the new host host1 to be part of any related groups, modifying /etc/nagios3/conf.d/hostgroups_nagios2.cfg

For example, we can add it to debian-servers and ssh-servers groups. This will automatically get some checks like SSH.

# Some generic hostgroup definitions

# A simple wildcard hostgroup
define hostgroup
        hostgroup_name  all
		alias           All Servers
		members         *
        }

# A list of your Debian GNU/Linux servers
define hostgroup {
        hostgroup_name  debian-servers
		alias           Debian GNU/Linux Servers
		members         localhost,host1
        }

# A list of your web servers
define hostgroup {
        hostgroup_name  http-servers
		alias           HTTP servers
		members         localhost
        }

# A list of your ssh-accessible servers
define hostgroup {
        hostgroup_name  ssh-servers
		alias           SSH servers
		members         localhost,host1
        }

Sources:
http://zeldor.biz/2010/11/nagios3-with-lighttpd/comment-page-1/
https://www.digitalocean.com/community/articles/how-to-install-nagios-on-ubuntu-12-10
http://cloud101.eu/blog/2012/03/01/setting-up-nagios-on-debian-or-ubuntu/
http://technosophos.com/2010/01/13/nagios-fixing-error-could-not-stat-command-file-debian.html

Managing your file system

We can use dumpe2fs utility to get info about our partition/drive.

This command will extract the details about the check interval.

dumpe2fs -h<span style="color: #ff0000;"> /dev/XXXx</span> | grep "Check interval"
or 
<strong>tune2fs -l /dev/sda1</strong>

To change this setting, you can issue this command, where NN is the number of mounts before re-checking it:

tune2fs -c <span style="color: #0000ff;"><em><strong>NN</strong></em></span> <span style="color: #ff0000;"> /dev/XXXx</span>

You can change the maximum number of mounts allowed before a full check is forced using the -c option, or change the interval between full checks with the -i option. The interval can be specified in days, months or weeks by appending a d, m or w to the number.

# tune2fs -c 10 /dev/hdd1

tune2fs 1.39 (29-May-2006)
Setting maximal mount count to 10

# tune2fs -i 30d /dev/hdd1

Source: http://www.dba-oracle.com/t_linux_tune2fs.htm

Change Filesystem Volume Name

Using the “-L” parameter, we can give add/change the filesystem volume name.

# tune2fs -L Disk_One /dev/sda1
tune2fs 1.41.9 (22-Aug-2009)

# tune2fs -l /dev/sda1 | grep volume
Filesystem volume name:   Disk_One

 

Displaying Filesystem Check Intervals and Mount Counts

By default, most systems will automatically attempt to check your filesystems after a defined time limit. This may be the number of times a filesystem has been mounted or literally a set time. To display the current settings we can use the “tune2fs” command and grep for “interval” and “count”.

# tune2fs -l /dev/sda1 |grep interval
Check interval:           15552000 (6 months)

# tune2fs -l /dev/sda1 |grep -i count
Inode count:              9609216
Block count:              38419456
Reserved block count:     1920972
Mount count:              6
Maximum mount count:      35

 

Disable Filesystem Check on Boot

The following parameters should only be used in a test environment where you may be carrying out multiple reboots during the course of the day. The Mount Count and check interval values below are set to “-1” which disables any checking!

tune2fs -c -1 /dev/sda1

tune2fs -i -1 /dev/sda1

 

Modifying Filesystem Checks

The following will modify the Check interval and Mount Count to only check after 100 mounts or a 2 month period.

tune2fs -c 100 -i 2m /dev/sda1

Staggering the mount counts at which filesystems are checked can avoid all filesystems being checked at one time. This will avoid all filesystems being checked at the same time and can reduce boot time.

Apache .htaccess for website password authentication

Quick notes… the ones that you are probably forgetting if you’re not using it….

Go inside your website folder website

Create a .htaccess file with the below content

AuthUserFile /var/www/website/.htpasswd
AuthGroupFile /dev/null
AuthName "Work forms"
AuthType Basic
require valid-user

Make sure the permissions are set correctly:

chmod ugo+r .htaccess

Then, create the user and the password:

htpasswd -c /var/www/website/.htpasswd your_user

Please note that the -c is to “create” the file. If you want to add other users, just remember to remove that flag or the file will be overwritten

In the VirtualServer section, make sure to have this:

<Directory "/var/www/<website>">
AllowOverride AuthConfig
</Directory>

Restart apache and… it should work 😛

BASH – File test operators

(From man bash)

The test command sorts using ASCII ordering.

-a file
              True if file exists.
-b file
              True if file exists and is a block special file.
-c file
              True if file exists and is a character special file.
-d file
              True if file exists and is a directory.
-e file
              True if file exists.
-f file
              True if file exists and is a regular file.
-g file
              True if file exists and is set-group-id.
-h file
              True if file exists and is a symbolic link.
-k file
              True if file exists and its ``sticky'' bit is set.
-p file
              True if file exists and is a named pipe (FIFO).
-r file
              True if file exists and is readable.
-s file
              True if file exists and has a size greater than zero.
-t fd
              True if file descriptor fd is open and refers to a terminal.
-u file
              True if file exists and its set-user-id bit is set.
-w file
              True if file exists and is writable.
-x file
              True if file exists and is executable.
-G file
              True if file exists and is owned by the effective group id.
-L file
              True if file exists and is a symbolic link.
-N file
              True if file exists and has been modified since it was last read.
-O file
              True if file exists and is owned by the effective user id.
-S file
              True if file exists and is a socket.
file1 -ef file2
              True if file1 and file2 refer to the same device and inode numbers.
file1 -nt file2
              True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.
file1 -ot file2
              True if file1 is older than file2, or if file2 exists and file1 does not.

Inetd Daemon

The inetd daemon is sometimes referred to as a Super-Server because it manages connections for many services. Instead of starting multiple applications, only the inetd service needs to be started. When a connection is received for a service that is managed by inetd, it determines which program the connection is destined for, spawns a process for that program, and delegates the program a socket. Using inetd for services that are not heavily used can reduce system load, when compared to running each daemon individually in stand-alone mode.

Configuration file is /etc/inetd.conf
After making a change, you need to restart/reload the server.

On Debian (and similar), inetd can be restarted with the following

# /etc/init.d/openbsd-inetd restart

On RedHat (and similar) using this:

# service inetd reload

Example of configuration and explanation:

For an example, telnet can be configured as follows:

telnet  stream  tcp6    nowait  root    /usr/sbin/telnetd      telnetd -a

The first word, telnet, is the official name of the service. It is resolved using the system database to map port numbers and protocols to service names. In this case, /etc/services should contain:

telnet          23/tcp

The second and third words describe the type of socket and underlying protocol respectively. The /etc/protocols database is consulted.

The fourth word is the wait/nowait switch. A single-threaded server expects inetd to wait until it finishes reading all the data. Otherwise inetd lets the server run and spawns new, concurrent processes for new requests.

The fifth word is the user name, from the /etc/passwd/ database, that the service program should run as.

Finally, the path and the arguments of an external program are given. As usual, the first argument is the program name. In the example, inetd is told to launch the program /usr/sbin/telnetd with the command line arguments telnetd -a. inetd automatically hooks the socket to stdin, stdout, and stderr of the server program.

Generally TCP sockets are handled by spawning a separate server to handle each connection concurrently. UDP sockets are generally handled by a single server instance that handles all packets on that port.

Sources
http://www.freebsd.org/doc/handbook/network-inetd.html
http://en.wikipedia.org/wiki/Inetd