Benutzer-Werkzeuge


Install debian in chroot on x86-architecture

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.

Preparations on PC

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

On Diskstation

Unpack the tar

 cd /volume1/
 gunzip debian.tar.gz
 tar -xvf debian.tar
 cd debian

mount proc

mount -t proc none ./proc

chroot it

chroot ./ /bin/bash

"Install" debian

/debootstrap/debootstrap --second-stage

adjust the hostname

 echo "diskstation" >/etc/hostname

replace diskstation with the hostname of your system ( „ and “ must be kept)

Copy hosts

 #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

chroot it again

 mount -t proc none ./proc
 chroot ./ /bin/bash

setup apt-get

 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

.

Adjust the firmware

Startup scripts (basic)

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

Startup scripts (advanced)

Start/Stop many processed

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

Terminate SSH

If one installs a ssh server in chroot then its very important to do the following:

  1. SSH MUST be terminated
  2. all loginshells need to be terminated

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

Mount a backup volume

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

Mount hardware from /dev

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)

Hold reboot until a backup is finished

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

end own scripts

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

Example script

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

IMPORTANT

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 :-)

Melden Sie sich an, um einen Kommentar zu erstellen.

Seiten-Werkzeuge