#!/bin/sh VERSION='0.3.3.g11' # # Copyright (C) 2002, Mark Lawrence # Copyright (C) 2002, Paul Sladen # # WARNING: This script has been changed by Thomas Gelf to meet the # following requirements: # # - static context ids at creation time # - context based disk limits # - "advanced" network configuration, meens changing interface name # (was buggy) and asking for a netmask (util-vserver uses netmask # from the host servers interface - this didn't work with our # "bridged-dummy-interface"-solution, as our dummy interface e0 was # configured 0.0.0.0 promisc # - IPROOTDEV has been removed (you should replace "eth0" with # "$INTERFACE" if you change it back. We are using only IPROOT, it # should be enhanced to support more interfaces and/or ip addresses # - we added "sched" to S_FLAGS, "fakeinit" was also added statically # (you should change it back to "$FAKEINIT") # - we set default nice level 1 for all our vservers - not really # necessary, change it back # - we are currently doing some tests with memory limits using ULIMIT # (please remove our settings) # - we did cosmetic changes to /etc/fstab, totally unnecessary, change # it back # - we have had also changed the created sources.list files, as we are # using apt-proxy on our host - this has been removed from this # script as it is too specific and only regards our local solution # - you can see "MAX_INODES" and "MAX_BLOCKS" in /etc/v../$VHOST.CONF # these settings have absolutely no effect, until you use our patch # against the vserver shell script in util-vserver v0.28 from Enrico # - we modified VREBOOT_LOCATION, please change it to the right path # - we create the halt/reboot/shutdown links in the vservers - the # links are created from the host server, so the path names seem # wrong but they are not because the links are symbolic # - we change all the $VHOST.conf files to mode 600 - in most cases # not necessary # - we added some "chattr -t" to prevent problems witch recursive +t # attributes # - hopefully I didn't forget to mention something important - just # run a "diff" to be absolutely sure # # USE THIS SCRIPT AT YOUR OWN RISK, as it has been tested on only one # machine to create something like 150 Vservers during our tests last # week. We didn't have any problem using it, but we are not responsible # if it deletes all your data, burns down your house or throws some eggs # on GWB when he talks bullshit next time :o) # # I would like to use this lines to thank my trainee Matthias Wurz for # his great work on the vserver project during the last two weeks! # # Install a virtual debian server (vserver) from a debian HTTP/FTP archive # # ---------------------------------------------------------------- # Configurable items: # Root directory of your virtual servers (probably shouldn't change this) VSERVER_ROOT="/vservers" # Packages to install in addition to the base defaults # MUST INCLUDE ALL DEPENDENCIES (seperated by "," commas) INSTALL_PACKAGES="less,dnsutils,wget,bzip2,ssh,rsync,libssl0.9.6,libdns5,libisc4,liblwres1,bind9-host,zlib1g,libbz2-1.0,traceroute" # Packages installed from within the vserver after it has # been setup (seperated by "," commas) EXTRA_PACKAGES="emacs20,lynx-ssl" # Packages to remove from the base defaults (seperated by "," commas) REMOVE_PACKAGES="dhcp-client,lilo,makedev,pcmcia-cs,ppp,pppconfig,pppoe,pppoeconf,setserial,syslinux,nano,fdutils,iptables,libpcap0,pciutils" # sysvinit services relating to hardware access to remove REMOVE_LINKS="klogd hwclock.sh setserial urandom networking umountfs halt reboot" # Architecture: overide on non-Debian host such as Redhat # otherwise dpkg will detect whether we are i386/powerpc/sparc/etc ARCH="" # Which debian distribution (warning: this has only been tested with woody) DIST="woody" # Local or nearest location of a debian mirror (must include the `/debian') MIRROR="http://ftp.uk.debian.org/debian" # Default network interface for vservers: INTERFACE="eth0" # Copy vreboot/vhalt/vshutdown utility into /usr/local/sbin/ COPY_VREBOOT="true" # Disk to add the context based quota hashes VROOTDISK="/dev/hda5" # ---------------------------------------------------------------- # Nothing from here on should need changing. # ---------------------------------------------------------------- # NOTE: debootstrap handles multiple MIRRORs, so there is no reason why # we shouldn't too--that way we could just let it build /etc/apt/sources.list usage () { cat << EOF 1>&2 usage: ${0##*/} [OPTIONS] --hostname x --domain y.z --ip 1.2.3.4 --netmask 255.255.255.0 --context 100 (see --help for more information) EOF } full_usage () { cat << EOF Usage: ${0##*/} [OPTIONS] --hostname x --domain y.z --ip 1.2.3.4 Creates a new Debian vserver by downloading packages via HTTP/FTP Options: -h, --help this help -V, --version copyright and version information --arch set target architecture (eg. --arch "i386") (autodetected on Debian host if dpkg available) --copy-vreboot install "vreboot/vshutdown/vhalt" --no-copy-vreboot don't install "vreboot/vshutdown/vhalt" --dist defaults to "woody", passed to debootstrap. --fakeinit use "/sbin/init" to boot vserver --interface interface for IP addresses (if not "eth0") --mirror Debian HTTP/FTP mirror (including the /debian) --sshkeys copy pub-keys to "/root/.ssh/authorized_keys" -v, --verbose show extra output during setup --vsroot location of "/vserver/" directory Required: --hostname hostname for new vserver (eg. "alpha") --domain dns domain for new vserver (eg. "example.com") --ip IPv4 address for new vserver --netmask IPv4 netmask for new vserver --context unique contextnumber for new vserver EOF } full_version () { cat << EOF ${0##*/} version $VERSION Copyright (c) 2002 Mark Lawrence Copyright (c) 2002 Paul Sladen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. EOF } parse_args () { while [ $# -gt 0 ] ; do #echo "parse_args() doing :$#: :$1: :$*:" case "$1" in --help|-h) full_usage shift exit 0 ;; --version|-V) full_version shift exit 0 ;; --arch) case "$2" in [a-z]*) ARCH="$2" ;; *) echo "${0##*/} error: $1 overrides dpkg autodetect on non-Debian host-servers" 1>&2 echo 'e.g. "i386"' 1>&2 exit 1 ;; esac shift 2 ;; --copy-vreboot) COPY_VREBOOT="true" shift ;; --no-copy-vreboot) COPY_VREBOOT="" shift ;; --dist) case "$2" in [a-z]*) DIST="$2" if [ "woody" != "$2" ]; then echo "${0##*/} warning: I only know how to do \"woody\", be careful!" 1>&2 fi ;; *) echo "${0##*/} error: $1 requires a Debian distribution" 1>&2 echo 'e.g. "woody"' 1>&2 exit 1 ;; esac shift 2 ;; --domain) case "$2" in [a-z]*[a-z]) VDOMAIN="$2" ;; *) echo "${0##*/} error: $1 requires a dns domain-name" 1>&2 echo 'e.g. "example.com"' 1>&2 exit 1 ;; esac shift 2 ;; --fakeinit) # Note space at beginning--this gets tagged straight on FAKEINIT=" fakeinit" shift ;; --hostname) case "$2" in [a-z]*[a-z0-9]) VHOST="$2" ;; *) echo "${0##*/} error: $1 must be a hostname for the vserver" 1>&2 echo 'e.g. "alpha"' 1>&2 exit 1 ;; esac shift 2 ;; --interface) case "$2" in [a-z]*) INTERFACE="$2" ;; *) echo "${0##*/} error: $1 must be followed by a network interface" 1>&2 echo 'e.g. "eth1"' 1>&2 exit 1 ;; esac shift 2 ;; --ip) # This does for an octet: ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) ;-) case "$2" in [0-9]*.[0-9]*.[0-9]*.[0-9]*) IP="$2" ;; *) echo "${0##*/} error: $1 requires a single IPv4 e.g. \"192.168.100.1\"" 1>&2 exit 1 ;; esac shift 2 ;; --netmask) case "$2" in [0-9]*.[0-9]*.[0-9]*.[0-9]*) NETMASK="$2" ;; *) echo "${0##*/} error: $1 requires a valid netmask e.g. \"255.255.255.0\"" 1>&2 exit 1 ;; esac shift 2 ;; --context) # give the vserver an unique context number case "$2" in [0-9]*) CONTEXT="$2" ;; *) echo "${0##*/} error: $1 requires a unique context number e.g. \"100\"" 1>&2 exit 1 ;; esac shift 2 ;; --mirror) case "$2" in [hf]*://*) MIRROR="$2" ;; *) echo "${0##*/} error: $1 requires a debian mirror" 1>&2 echo 'e.g. "http://ftp.uk.debian.org/debian"' 1>&2 exit 1 ;; esac shift 2 ;; --verbose|-v) export verbose="true" shift ;; --sshkeys) if [ -f "$2" ]; then SSH_KEYS="$2" else echo "${0##*/} error: $1 must be followed by a valid public-key-file!" 1>&2 echo 'e.g. "/root/.ssh/id_dsa.pub"' 1>&2 exit 1 fi shift 2 ;; --vsroot) case "$2" in /*) if [ -d "$2" ]; then VSERVER_ROOT="$2" else echo "${0##*/} error: $1 needs a valid absolute directory" 1>&2 echo 'e.g. "/vservers"' 1>&2 exit 1 fi ;; *) echo "${0##*/} error: $1 needs a valid absolute directory" 1>&2 echo 'e.g. "/vservers"' 1>&2 exit 1 ;; esac shift 2 ;; -*) usage exit 1 ;; ?*) usage exit 1 ;; esac done } parse_args $@ if ! [ -n "$VHOST" -a -n "$VDOMAIN" -a -n "$IP" ]; then echo "${0##*/} error: --hostname, --domain and --ip are required" 1>&2 usage exit 1 fi # Strip final slashes off a couple of things MIRROR="${MIRROR%/}" VSERVER_ROOT="${VSERVER_ROOT%/}" # Check we've got debootstrap available if [ ! -x /usr/sbin/debootstrap ]; then cat << EOF 1>&2 ${0##*/}: Requires the debootstrap package to bootstrap Debian Debian Host: apt-get install debootstrap RPM Host: rpm -i http://people.debian.org/~blade/install/debootstrap/debootstrap-0.1.17.3-2.i386.rpm EOF exit 1 fi if ! cat /proc/self/status | grep '^s_context:[^0-9]0$'; then echo "${0##*/} error:" echo " Must be run from the host server (security context 0)" 1>&2 echo ' on a "vserver/ctx-patch" enabled kernel' 1>&2 echo ' See: http://www.solucorp.qc.ca/miscprj/s_context.hc' 1>&2 exit 1 fi if [ -x /usr/bin/id ] && [ `id -u` -ne 0 ]; then echo "${0##*/} error: Must be run as root!" 1>&2 exit 1 fi # check for /vserver/$VHOST/etc/ incase we are on pre-mounted LVM partition # (used to just check for "/vserver/$VHOST/" existing if [ -d "$VSERVER_ROOT/$VHOST/etc/" -o -f "/etc/vservers/$VHOST.conf" ] ; then cat << EOF 1>&2 ${0##*/} error: Virtual Server "$VHOST" appears to already exist check "/etc/vservers/$VHOST.conf" or "/vservers/$VHOST/etc/"; EOF exit 1 fi # This is used to keep a cache of the downloaded .deb packges for next install if [ -d "$VSERVER_ROOT/ARCHIVES" ]; then mkdir -p "$VSERVER_ROOT/$VHOST" chattr -t "$VSERVER_ROOT/$VHOST" mkdir -p "$VSERVER_ROOT/$VHOST/var/cache/apt/archives" cp -a "$VSERVER_ROOT/ARCHIVES/"*.deb "$VSERVER_ROOT/$VHOST/var/cache/apt/archives" fi # We only want to pass the Architecture if we need to (autodectected otherwise) if [ -n "$ARCH" ]; then ARCH_ARGUMENT="--arch $ARCH" fi # Fire off `debootstrap' to do all the hard work # like downloading and installing if ! /usr/sbin/debootstrap $ARCH_ARGUMENT \ "--include=$INSTALL_PACKAGES" "--exclude=$REMOVE_PACKAGES" \ "$DIST" "$VSERVER_ROOT/$VHOST" "$MIRROR" ; then echo "${0##*/}: error: debootstrap failure. Cannot continue." exit 1 fi # Make it so that apt and friends work cat << EOF > "$VSERVER_ROOT/$VHOST/etc/apt/sources.list" deb $MIRROR/ stable main non-free contrib deb-src $MIRROR/ stable main non-free contrib deb http://non-us.debian.org/debian-non-US stable/non-US main contrib non-free deb-src http://non-us.debian.org/debian-non-US stable/non-US main contrib non-free deb http://security.debian.org stable/updates main contrib non-free EOF # Fix up the available device nodes, for security if cd "$VSERVER_ROOT/$VHOST/dev"; then tar cfp /tmp/dev.tar.$$ full null ptmx random tty urandom zero rm -rf $VSERVER_ROOT/$VHOST/dev/* tar xfp /tmp/dev.tar.$$ rm /tmp/dev.tar.$$ mkdir pts mkdir shm fi # Give the new host a hostname echo "$VHOST" > "$VSERVER_ROOT/$VHOST/etc/hostname" # Set up the /etc/hosts file (needed for some parts of the base-config) cat << EOF > "$VSERVER_ROOT/$VHOST/etc/hosts" # /etc/hosts 127.0.0.1 localhost $IP $VHOST.$VDOMAIN $VHOST # The following lines are desirable for IPv6 capable hosts # (added automatically by netbase upgrade) ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts EOF # grab DNS servers from the host-server for `resolv.conf' (echo search $VDOMAIN ; grep '^nameserver' /etc/resolv.conf) \ > "$VSERVER_ROOT/$VHOST/etc/resolv.conf" # If there is a proxy server statement in-use in the Host server, copy it across if [ -f /etc/apt/apt.conf ]; then cp /etc/apt/apt.conf $VSERVER_ROOT/$VHOST/etc/apt/apt.conf fi # This old uname was putting the name of the *host* into the vserver motd # uname -a > $VSERVER_ROOT/$VHOST/etc/motd # Create a shorter motd (uname -a would give name of host-server) echo "Debian GNU/Linux ($DIST/$(uname -m)) $VHOST.$VDOMAIN" \ > "$VSERVER_ROOT/$VHOST/etc/motd" # Create a dummy fstab cat << EOF > "$VSERVER_ROOT/$VHOST/etc/fstab" # /etc/fstab: static file system information. # # /dev/hdv1 / vfs defaults 0 0 proc /proc proc defaults 0 0 devpts /dev/pts devpts rw,gid=5,mode=620 0 0 EOF # The new vserver patch now automatically mounts /proc # Debian needs /dev/pts mounting "gid=5,mode=620" by vserver cat << EOF > "$VSERVER_ROOT/$VHOST/etc/mtab" /dev/hdv1 / vfs none 0 0 proc /proc proc rw 0 0 devpts /dev/pts devpts rw,gid=5,mode=620 0 0 EOF # Create a reduced inittab that doesn't start getty on the consoles cat << EOF > "$VSERVER_ROOT/$VHOST/etc/inittab" # /etc/inittab: init(8) configuration. # The default runlevel. id:2:initdefault: # Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS # What to do in single-user mode. ~~:S:wait:/sbin/sulogin # /etc/init.d executes the S and K scripts upon change # of runlevel. # # Runlevel 0 is halt. # Runlevel 1 is single-user. # Runlevels 2-5 are multi-user. # Runlevel 6 is reboot. l0:0:wait:/etc/init.d/rc 0 l1:1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6 EOF # By default the Debian Install script runs zillions of cron jobs at # 0625 every morning. On a system with lots of vservers all trying to # scan the disk at the same time this causes $MAJOR disk-thrash. So # we randomize it a bit so that they run evenly between 1am and 7am, # avoiding the 5minutes either side of the hour when other stuff tends # to be scheduled. (BTW, this solution is Overkill!) # This looks over complicated--and it probably is...: # # a) We want the DAILY jobs to run between :05 and :55 minutes past # b) We want the WEEKLY job 3-5 minutes after the DAILY. # c) And the MONTHLY job 3-5 minutes after that. # d) Make sure all three jobs are started by 55minutes past (five-to) # ...if they were ever to all run on the same day! d1=$(($RANDOM % 3 + 3)); # between 3 and 5 d2=$(($RANDOM % 3 + 3)); # between 3 and 5 dt=$((50 - $d1 - $d2)); # between 0 and 44 DAILY=$(($RANDOM % $dt + 5)) # between 5 and 49 WEEKLY=$(($DAILY + $d1)) # between 8 and 52 MONTHLY=$(($WEEKLY + $d2)) # between 11 and 55 HOUR=$(($RANDOM % 6 + 1)) # between 1 and 7 (AM localtime) # Create replacement /etc/crontab with randomized times above cat << EOF > "$VSERVER_ROOT/$VHOST/etc/crontab" # /etc/crontab: system-wide crontab # Unlike any other crontab you don't have to run the \`crontab\' # command to install the new version when you edit this file. # This file also has a username field, that none of the other crontabs do. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # m h dom mon dow user command $DAILY $HOUR * * * root test -e /usr/sbin/anacron || run-parts --report /etc/cron.daily $WEEKLY $HOUR * * 7 root test -e /usr/sbin/anacron || run-parts --report /etc/cron.weekly $MONTHLY $HOUR 1 * * root test -e /usr/sbin/anacron || run-parts --report /etc/cron.monthly EOF # Create default /etc/vservers conf entry cat << EOF > /etc/vservers/$VHOST.conf IPROOT="$INTERFACE:$IP/$NETMASK" S_HOSTNAME="$VHOST" S_DOMAINNAME="" S_NICE="1" S_CONTEXT="$CONTEXT" S_FLAGS="lock nproc fakeinit sched" ULIMIT="-HS -u 1000 -v 262144 -l 131072 -m 131072 -n 1024" ONBOOT="yes" S_CAPS="CAP_NET_RAW" VROOTDISK="$VROOTDISK" MAX_INODES="100000" MAX_BLOCKS="1048576" EOF chmod 600 /etc/vservers/$VHOST.conf if [ -n "$EXTRA_PACKAGES" ]; then EXTRA_PACKAGES_INSTALL="apt-get --assume-yes install ${EXTRA_PACKAGES//,/ }" fi # ------------------------------------------------------------ # From here on we do things live in the server # Generate the script that runs the rest of the setup from within the # virtual server. cat << EOF > $VSERVER_ROOT/$VHOST/vserver-config.sh #!/bin/sh dselect update tzsetup -y dpkg-reconfigure passwd tasksel rm -f /etc/exim/exim.conf eximconfig # because the --exclude flag doesn\'t seem to work on debootstrap apt-get --assume-yes --purge remove `echo $REMOVE_PACKAGES | sed -e 's/,/ /g'` for link in $REMOVE_LINKS do update-rc.d -f \$link remove done $EXTRA_PACKAGES_INSTALL EOF # Run the above commands from within the server chmod 755 $VSERVER_ROOT/$VHOST/vserver-config.sh vserver $VHOST exec /vserver-config.sh rm -f $VSERVER_ROOT/$VHOST/vserver-config.sh # If you need to install your SSH management keys into the vserver if [ -f "$SSH_KEYS" ]; then mkdir -p "$VSERVER_ROOT/$VHOST/root/.ssh" chmod 700 "$VSERVER_ROOT/$VHOST/root/.ssh/" cat "$SSH_KEYS" >> "$VSERVER_ROOT/$VHOST/root/.ssh/authorized_keys" chmod 600 "$VSERVER_ROOT/$VHOST/root/.ssh/authorized_keys" fi # Install the vreboot/rebootmgr utility--hopefully this will disappear soon VREBOOT_LOCATION="/usr/local/lib/util-vserver/vreboot" if [ "$COPY_VREBOOT" == "true" -a -x "$VREBOOT_LOCATION" ]; then cp -a "$VREBOOT_LOCATION" "$VSERVER_ROOT/$VHOST/usr/local/sbin/vreboot" chmod 750 "$VSERVER_ROOT/$VHOST/usr/local/sbin/vreboot" ln -sf "/usr/local/sbin/vreboot" "$VSERVER_ROOT/$VHOST/sbin/halt" ln -sf "/usr/local/sbin/vreboot" "$VSERVER_ROOT/$VHOST/sbin/reboot" ln -sf "/usr/local/sbin/vreboot" "$VSERVER_ROOT/$VHOST/sbin/shutdown" fi # Stop all the processes that were started inside the server export PREVLEVEL=2 vserver $VHOST exec /etc/init.d/rc 0 vserver $VHOST stop # Populate the archive for future virtual servers if [ ! -d $VSERVER_ROOT/ARCHIVES ]; then mkdir $VSERVER_ROOT/ARCHIVES chattr -t $VSERVER_ROOT/ARCHIVES fi cp $VSERVER_ROOT/$VHOST/var/cache/apt/archives/*.deb $VSERVER_ROOT/ARCHIVES echo echo "You should now adjust /etc/vservers/$VHOST.conf to suit your needs," echo "or else just go ahead and type \`vserver $VHOST start' to start" echo "your new virtual server. debian/rules!" echo