This is a small guide to install a (almost) complete debian on a diskstation with Intel x86-processor. The sweet thing about this is that you can install this debian within the firmware of the diskstation. The firmware and the choot do not bite each other. This page describes how to install on a DS1511+, but should work for all diskstations which their processors are supported by debian. Works for all x86 from Intel and on certain ARM and PPC.
This guide requires that you perform some preparing steps on a debian PC. For a x86-processor one could skip these steps on the PC and download the required tar archive from my page here for my 1511+. Should work with every Intel processor
I cannot in any way be responsible for this description and cannot guarantuee that it will always work. The chances to „destroy“ a running system although are very low with a chroot. But anyway the user is responsible for what he/she does on his/her system!
Thanks @ubuntulinux for the german version, which this english version is based on
The goal of all this is to install a debian within the firmware. The main advantage of this approach is that you still can use the firmware, but also can access to the thousands of debian packages that exist. Because a chroot is used the two systems are completly segregated. This means for processes in debian chroot it is impossible to access files that are outside the chroot-jail (ex firmware files). The other way around though is possible: You can access to files from the chroot from outside the chroot.
One need a Debian-PC, to download the data and prepare them for chroot. On this PC type the following in a shell:
apt-get install debootstrap -y apt-get clean debootstrap --foreign --arch amd64 squeeze debian "http://ftp.de.debian.org/debian"
Please change amd64 with your architecture on the DS. This works for Intel processors
After the process has finished pack the data to a tar with the following command
tar -xvzf debian.tar.gz
After that copy/move the archive to your diskstation. I prefer directly on /volume1/, makes it easier to handle. All the page here assumes you name the file debian.tar.gz and copy it to /volume1/debian.tar.gz on DS. Although it can be anywhere
cd /volume1/ gunzip debian.tar.gz tar -xvf debian.tar cd debian
mount -t proc none ./proc
chroot ./ /bin/bash
/debootstrap/debootstrap --second-stage
echo "diskstation" >/etc/hostname
replace diskstation with the hostname of your system ( „ and “ must be kept)
#exit leaves the chroot exit cp /etc/hosts ./etc/hosts
with exit we leave the chroot and the we copy the /etc/hosts from firmware into the filesystem of the chroot
mount -t proc none ./proc chroot ./ /bin/bash
nano -w /etc/apt/sources.list
Add the following:
deb http://ftp2.de.debian.org/debian/ squeeze main deb-src http://ftp2.de.debian.org/debian/ squeeze main deb http://security.debian.org squeeze/updates main
Then type on console
apt-get update apt-get upgrade apt-get dist-upgrade
Now you have the latest debian squeeze installed. When ever you want to change into the chroot, type the following from a shell within your firmware (don't type the following if you are already inside the chroot!!):
mount -t proc none /volume1/debian/proc chroot /volume1/debian /bin/bash
To leave a chroot just type
exit
.
A chroot cannot start its processes automatically on boot of the diskstation. You need a startup script which is called from the bootprocess of the firmware. This startup script then stops/starts processes within chroot. A place to put this script into could be /usr/syno/etc.defaults/rc.d/
or (better) /opt/etc/init.d/
.
Very important: This script MUST stop all processes that are launched inside chroot AND MUST remove all mounts for that chroot. If the script only misses one open loginshell or any mount for the chroot, the shutdown/reboot of the diskstation WILL always fail. So its very important to have a proper script!!
Here an example how one could start a installed apache in chroot
#!/bin/sh if [ "$*" = 'start' ] ; then chroot /volume1/debian /etc/init.d/apache2 start else chroot /volume1/debian /etc/init.d/apache2 stop fi
the first path after the chroot command is the base path of the „chroot“. The command following will be executed within that base directory
It is important to add/remove mounts. Especially when shutting down a single mount could halt the whole shutdown:
#!/bin/sh if [ "$*" = 'start' ] ; then mount -t proc none /volume1/debian/proc chroot /volume1/debian /etc/init.d/apache2 start else chroot /volume1/debian /etc/init.d/apache2 stop umount /volume1/debian/proc fi
keep the following in mind: If start then first mount the necessary stuff and then start the processes. If shutdown then first stop all processes and then remove the mounts
As soon as the list of processes in chroot exceeds a certain number, it would be very „stressfull“ to type the lines like above for every process. To make this easier the for-loop is perfect
#!/bin/sh case "$*" in 'start') for i in cron apache2 postfix dovecot dnsmasq lighttpd webmin ; do chroot /volume1/debian /etc/init.d/$i start done ;; 'stop') for i in cron apache2 postfix dovecot dnsmasq lighttpd webmin ; do chroot /volume1/debian /etc/init.d/$i stop done ;; *) echo 'Usage stop|start' ;; esac
If one installs a ssh server in chroot then its very important to do the following:
1) its easy to achive. Just amend you startupscript to include ssh 2) a lot of people forget that As long as just one login session - and kill ssh DOES NOT terminate those - is open you cannot umount the pts. The shutdown halts. To be sure that all loginshell from chroot are terminated it can be helpful to keep in mind that the default logon shell from chroot is bash, whereas the firmware uses sh or ash. This makes it easy to write some code which kills all bash Shells.
This disadvantage of this approach is if you have stuff outside your chroot which uses bash processes too. All of them would be killed too
#!/bin/sh case "$1" in 'start') echo "$(date '+%d.%m.%Y %H:%M:%S') Starting debian chroot" mount -t proc none /volume1/debian/proc > /dev/null 2>&1 mount -t devpts devpts /volume1/debian/dev/pts > /dev/null 2>&1 for i in ssh ; do chroot /volume1/debian /etc/init.d/$i start done ;; 'stop') echo "$(date '+%d.%m.%Y %H:%M:%S') Stoping debian chroot" for i in ssh ; do chroot /volume1/debian /etc/init.d/$i stop done for i in $(ps | grep '\-bash' | grep -v grep | awk '{print $1}') ; do kill -s 9 $i > /dev/null 2>&1 done umount /volume1/debian/proc umount /volume1/debian/dev/pts ;; esac
It can be very helpful to mount a directory outside the chroot for the backup of chroot. I have my chroot on volume1. A subfolder from my volume2 is mounted into the chroot as backup volume
#!/bin/sh if [ "$*" = 'start' ] ; then mkdir -p /volume1/debian/backup mount --bind /volume2/.debian_backup /volume1/debian/backup fi
DONT'T forget to remove this mount on stop Inside the chroot you can save data to /backup and the data ends up in /volume2/.debian_backup
As the start script runs outside the chroot it has access to hardware in /dev and therefore can mount stuff into the chroot. One could try to mount –bind the entire /dev for the chroot. But problems will be guaranteed. It better to only mount what is really needed
#!/bin/sh if [ "$*" = 'start' ] ; then #make LEDs available for chroot mount --bind /dev/ttyS1 /volume1/debian/dev/ #mount a partition for chroot mount /dev/sdk1 /volume1/debian/dev/ fi
about the LED stuff check check out our wiki (german)
IMPORTANT: If you plan to mount an entiere drive or partition be sure that the source is not already mounted by the firmware If already mounted better use mount –bind to make it available for chroot (see above with the backup-part)
It can be „not wished“ that a reboot/shutdown is performed when a backup job is still running. It's very easy to delay the shutdown/reboot in the script. I used the process rsnapshot here as example
#!/bin/sh if [ "$*" = 'stop' ] ; then [ -n "$(ps | grep rsnapshot | grep -v grep)" ] && echo "$(date '+%d.%m.%Y %H:%M:%S') Backup running. Delay Shutdown" while [ -n "$(ps | grep rsnapshot | grep -v grep)" ] do echo "$(date '+%d.%m.%Y %H:%M:%S') Checking again in 30s" sleep 30 echo "$(date '+%d.%m.%Y %H:%M:%S') Checking for backup running..." done echo "$(date '+%d.%m.%Y %H:%M:%S') Backup ended or not running. Resume Shutdown/Reboot" fi
Often the admin (aka root) has scripts that run i a infinite loop. Can be usefull if a script must be executed more often than the minimal interval of cron allows (1 min). To kill such processes you can use something like that
#!/bin/sh if [ "$*" = 'stop' ] ; then for i in script script.sh script1.php script2.pl script3.py sleep ; do for ii in $(ps | grep $i | grep -v grep | awk '{print $1}') ; do kill -s 9 $ii done done fi
This is an example script of how one could achive quite complex stuff. Do not just copy & paste this script
#!/bin/sh case "$1" in 'start') echo "$(date '+%d.%m.%Y %H:%M:%S') Starting debian chroot" mount --bind /volume2/.backup/servers /volume1/@debian/backup >> /opt/var/log/debian.log 2>&1 mount --bind /dev/ttyS1 /volume1/@debian/dev/ttyS1 >> /opt/var/log/debian.log 2>&1 mount -t proc none /volume1/@debian/proc >> /opt/var/log/debian.log 2>&1 mount -t devpts devpts /volume1/@debian/dev/pts >> /opt/var/log/debian.log 2>&1 mount --bind /dev/net/tun /volume1/@debian/dev/net/tun >> /opt/var/log/debian.log 2>&1 for i in syslog-ng dnsmasq fail2ban munin-node ssh ntp clamav-daemon clamav-freshclam clamav-milter spamassassin postgrey postfwd opendkim dovecot imapproxy postfix mailmanctl mailgraph mysql lighttpd pound webmin vsftpd cron ; do logger -p daemon.error "Start $i" echo -n "$(date '+%d.%m.%Y %H:%M:%S') Starting $i ... " [ "$i" = 'mailmanctl' ] && chroot /volume1/@debian su mailman -c "/home/mailman/bin/$i start" >> /opt/var/log/debian.log 2>&1 [ ! "$i" = 'mailmanctl' ] && chroot /volume1/@debian /etc/init.d/$i start >> /opt/var/log/debian.log 2>&1 t=$? [ $t -ne 0 ] && logger -p daemon.error "Error for $i" && echo 'failed' [ $t -eq 0 ] && echo "sucess" done # echo "$(date '+%d.%m.%Y %H:%M:%S') Start getmaild" # chroot /volume1/@debian /root/restart_getmaild.sh start & >> /opt/var/log/debian.log 2>&1 echo "$(date '+%d.%m.%Y %H:%M:%S') Start openVPN-Stat" chroot /volume1/@debian /root/openVPN-Stat.sh & >> /opt/var/log/debian.log 2>&1 echo "$(date '+%d.%m.%Y %H:%M:%S') All started" sleep 1 ;; 'stop') echo "$(date '+%d.%m.%Y %H:%M:%S') Shut down debian chroot" [ -n "$(ps | grep rsnapshot | grep -v grep)" ] && echo "$(date '+%d.%m.%Y %H:%M:%S') Backup running. Delay Shutdown" while [ -n "$(ps | grep rsnapshot | grep -v grep)" ] do echo "$(date '+%d.%m.%Y %H:%M:%S') Checking again in 30s" sleep 30 echo "$(date '+%d.%m.%Y %H:%M:%S') Checking for backup running..." done echo "$(date '+%d.%m.%Y %H:%M:%S') Backup ended or not running. Resume Shutdown/Reboot" for i in $(ps | grep checkBlog | grep -v grep | awk '{print $1}') do kill -s 9 $i >> /opt/var/log/debian.log 2>&1 done umount /volume1/@debian/backup >> /opt/var/log/debian.log 2>&1 [ -n "$(cat /volume1/@debian/tmp/getmail.pid)" ] && kill $(cat /volume1/@debian/tmp/getmail.pid) >> /opt/var/log/debian.log 2>&1 echo > /volume1/@debian/tmp/getmail.pid && echo > /volume1/@debian/tmp/checkmaill for i in cron vsftpd webmin pound lighttpd mysql mailgraph mailmanctl postfix imapproxy dovecot opendkim postfwd postgrey spamassassin clamav-milter clamav-freshclam clamav-daemon ntp ssh munin-node fail2ban dnsmasq syslog-ng ; do echo -n "$(date '+%d.%m.%Y %H:%M:%S') Stop $i .. " logger -p daemon.error "Stop $i" [ "$i" = 'mailmanctl' ] && chroot /volume1/@debian su mailman -c "/home/mailman/bin/$i stop" >> /opt/var/log/debian.log 2>&1 && killall $i >> /opt/var/log/debian.log 2>&1 [ ! "$i" = 'mailmanctl' ] && chroot /volume1/@debian /etc/init.d/$i stop >> /opt/var/log/debian.log 2>&1 [ $? -ne 0 ] && logger -p daemon.error "Error for $i" echo "sucess" done for i in checkIP.php openVPN-Stat.sh server.php getmail sleep mysql do for ii in $(ps | grep $i | grep -v grep | awk '{print $1}') do kill -s 9 $ii >> /opt/var/log/debian.log 2>&1 done done for i in $(ps | grep '\-bash' | grep -v grep | awk '{print $1}') do kill -s 9 $i >> /opt/var/log/debian.log 2>&1 done umount -f /volume1/@debian/dev/ttyS1 >> /opt/var/log/debian.log 2>&1 umount -f /volume1/@debian/proc >> /opt/var/log/debian.log 2>&1 umount -f /volume1/@debian/dev/pts >> /opt/var/log/debian.log 2>&1 umount -f /volume1/@debian/dev/net/tun >> /opt/var/log/debian.log 2>&1 sleep 1 ;; *) echo 'Usage start|stop' ;; esac
TEST your script before you perform a reboot/shutdown. Chances are high that you missed a proccess of chroot or a mount. That would result in a failing reboot/shutdown. The station would hang! Call the script with the stop parameter and check with htop that no process from within chroot is still running. Ensure with mount that no mount for the chroot remains. Don't forget to test the start parameter of the script too!
It can only be outlined: Test it, test it again and do it again Sam