How to setup a Debian server on gandi.net
NOTE: I wrote this guide when gandi.net didn't offer Debian Lenny (5.0) images, now they do, so for a new server you want to skip the upgrade part of this document.
Contents
Server Setup
- Create and Login with your Gandi.net handle, after login you could even request a trial if you are considering purchasing a VPS at Gandi.
Create a server
Go to the Manage->Servers panel and Create a Server:
- Choose the numer of shares you want (2 in my case) and Submit
- Select Installation Mode: Gandi MI (Manual Install) with Debian4 for me.
- Configure your server choosing hostname, username and password
- Wait for server creation, now in the server list you can click on server hostname to see the details (show IP address, edit configuration, get a reverse DNS entry)
Let's say that for documentation purposes (see RFC3330) your server is at 192.0.2.1
and its hostname is example.com
.
Fix debian4 image
This is needed to make ssh public key authentication work properly:
- Login to your server
user@localhost:~$ ssh username@192.0.2.1
and put the password you choose before. - Check
/home
permissions and fix themusername@example.com:~$ ls -l /home total 4 drwxrws--- 2 username username 4096 2009-03-17 10:07 username username@example.com:~$ chmod 0755 /home/username username@example.com:~$ ls -l /home total 4 drwxr-xr-x 2 username username 4096 2009-03-17 10:07 username
(inspired by this)You could even be more conservative and use mode
0711
but we are liberal :)
Use ssh public key authentication
Now you can upload your pubkey to the server (you'll need to create it if you don't have one already):
user@localhost:~$ ssh-copy-id -i ~/.ssh/id_rsa.pub username@192.0.2.1
You could add this key also to root@example.com
, you choose.
Upgrade to latest stable debian release
At the time of writing the latest debian release is Debian 5.0 (Lenny).
- Upgrade etch packages:
username@example.com:~$ su - Password: root@example.com:~# aptitude
- Upgrade to Lenny:
- Setup Lenny repositories in
/etc/apt/sources.list
as said here:# Old entries commented #deb http://mirrors.gandi.net/debian/ etch main contrib non-free #deb http://security.debian.org/debian-security etch/updates main contrib non-free deb http://mirrors.gandi.net/gandi/debian etch main deb http://ftp.debian.org/debian/ lenny main contrib non-free deb-src http://ftp.debian.org/debian/ lenny main contrib non-free deb http://security.debian.org/debian-security lenny/updates main contrib non-free deb-src http://security.debian.org/debian-security lenny/updates main contrib non-free
-
Prepare for upgrade as suggested here:
root@example.com:~# aptitude update root@example.com:~# mv /lib/tls/i686 /lib/tls/i686.old root@example.com:~# aptitude install libc6 libc6-xen root@example.com:~# aptitude install apt dpkg aptitude root@example.com:~# aptitude full-upgrade
- Do some cleanup, remove obsolete and unneeded packages, purge config for autoremoved packages, run deborphan, etc.
- Setup Lenny repositories in
Stop and restart the server from gandi.net control panel, you now have your shiny Lenny VPS.
NOTE: If you get this warning on boot:
*************************************************************** *************************************************************** ** WARNING: Currently emulating unsupported memory accesses ** ** in /lib/tls glibc libraries. The emulation is ** ** slow. To ensure full performance you should ** ** install a 'xen-friendly' (nosegneg) version of ** ** the library, or disable tls support by executing ** ** the following as root: ** ** mv /lib/tls /lib/tls.disabled ** ** Offending process: init (pid=680) ** *************************************************************** ***************************************************************
you can edit /etc/ld.so.conf.d/libc6-xen.conf
and put this line:
hwcap 0 nosegneg
instead of the one present, and then run ldconfig
.
This is a workaround, and we should revert it the day Gandi updates the kernel.
Basic Setup
IMPORTANT:
Add your hostname to /etc/hosts
, to make gethostbyname()
work, a line like the one below is enough.
192.0.2.1 example.com
Add some handy packages like ntpdate deborphan, iproute, sysv-rc-conf, psmisc, rsync and screen, copy your dot-files to the server.
Disable inetd if you don't need it: update-rc.d -f openbsd-inetd remove && kill -9 `pidof inetd`
Run dpkg-reconfigure tzdata
, and set UTC as timezone.
Securing the server
Some hardening, following the Securing Debian Howto
- Iptables setup, this is the script I used to test the rules, a very simple one inspired from madduck, it can be made more explicit but it is ok to give the idea:
#!/bin/bash # iptables script, generated from iptables-save file IPT='/sbin/iptables' # $ ip addr show dev eth0 # 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000 # link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff # inet 192.0.2.1/24 brd 192.0.2.255 scope global eth0 # valid_lft forever preferred_lft forever MY_IFACE="eth0" MY_IP="192.0.2.1" $IPT -t raw -F $IPT -t raw -X $IPT -t mangle -F $IPT -t mangle -X $IPT -t nat -F $IPT -t nat -X $IPT -t filter -F $IPT -t filter -X $IPT -P INPUT ACCEPT $IPT -P FORWARD ACCEPT $IPT -P OUTPUT ACCEPT $IPT -N in-new # allow all loopback traffic $IPT -A INPUT -i lo -j ACCEPT $IPT -A OUTPUT -o lo -j ACCEPT # Ingress and egress filtering $IPT -A INPUT -i $MY_IFACE -s $MY_IP -j DROP $IPT -A OUTPUT -o $MY_IFACE -s ! $MY_IP -j DROP $IPT -A INPUT -i $MY_IFACE -s 0.0.0.0/8 -j DROP $IPT -A INPUT -i $MY_IFACE -s 127.0.0.0/8 -j DROP $IPT -A INPUT -i $MY_IFACE -s 10.0.0.0/8 -j DROP $IPT -A INPUT -i $MY_IFACE -s 172.16.0.0/12 -j DROP $IPT -A INPUT -i $MY_IFACE -s 192.168.0.0/16 -j DROP $IPT -A INPUT -i $MY_IFACE -s 224.0.0.0/3 -j DROP ### INPUT chain # allow all ICMP traffic $IPT -A INPUT -p icmp -j ACCEPT # packets belonging to an established connection or related to one can pass $IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # packets that are out-of-sequence are silently dropped $IPT -A INPUT -m state --state INVALID -j DROP # new connections unknown to the kernel are handled in a separate chain $IPT -A INPUT -m state --state NEW -j in-new # pass SYN packets for SSH $IPT -A in-new -p tcp -m tcp --dport 22 --syn -j ACCEPT # pass SYN packets for HTTP $IPT -A in-new -p tcp -m tcp --dport 80 --syn -j ACCEPT # log everything else $IPT -A INPUT -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[INPUT]: " # Add a limit criterion to the REJECT rule and start DROPping instead if the limit is # excedded? This could save some bandwidth. $IPT -A INPUT -j REJECT ### OUTPUT chain # allow outgoing traffic, explicitly (despite chain policy) $IPT -A OUTPUT -j ACCEPT ### FORWARD chain # disallow forwarded traffic, explicitly (despite chain policy) $IPT -A FORWARD -j REJECT
after you loaded the rules from the test script you can save them with:
iptables-save > /etc/network/iptables.rules
And add the command to reload them on boot in
/etc/network/interfaces
:pre-up iptables-restore < /etc/network/iptables.rules
in your interface settings, you may also want to remove
/etc/network/interfaces.dhcp
since you don't need it and it will overwrite/etc/network/interfaces
on boot. -
We could even use ulog to log the firewall messages:
Install ulogd
aptitude install ulogd ulogd-mysql
Config mysql:
mysqladmin -u root -p CREATE ulogd mysql -u root -p ulogd < /usr/share/doc/ulogd-mysql/mysql.table mysql -u root -p mysql> USE ulogd; mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON ulogd.ulog TO 'ulogd_user'@'localhost' IDENTIFIED BY 'ulogd_passwd'; mysql> flush privileges; mysql> quit
Edit the config file to enable and configure the mysql output plugin if needed
/etc/ulogd.conf
Change the firewall script to log to ULOG target, all the lines above with LOG become like:
$IPT -A INPUT -m limit --limit 3/min --limit-burst 10 -j ULOG --ulog-nlgroup 1 --ulog-prefix "[INPUT]: "
And reboot ulogd:
invoke-rc.d ulogd restart
- Install debsecan
- try also the harden package, it will install many tools for checking and improving the security of your system, but you should really sneak a glance at the Securing Debian Howto anyway.
Add a disk
Go to the Manage->Servers panel and Add a disk to your server:
- Click on the Disk management tab
- If you want to purchase more space click on Add quota
- Click on Create a Disk
- Chose a logical name (e.g. disk01), a size and a filesystem (the filesystem doesn't matter, we will repartition the disk anyway)
- Wait that disk creation completes and attach the disk to a server
- Disable the automounter: edit
udev/rules.d/86-gandi.rules
and comment the line.
Reformat the disk space
We will use LVM, following this guide so we can extend the layout in future if needed, our "physical" disk is /dev/xvdb
.
aptitude install lvm2
create the partition table:
fdisk /dev/xvdb n p 1 t 8e
create physiscal volume:
pvcreate /dev/xvdb1
create a volume group called data:
vgcreate data /dev/xvdb1
display the volume group info:
vgdisplay --- Volume group --- VG Name data System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 1 VG Access read/write VG Status resizable MAX LV 0 Cur LV 0 Open LV 0 Max PV 0 Cur PV 1 Act PV 1 VG Size 10.00 GB PE Size 4.00 MB Total PE 2559 Alloc PE / Size 0 / 0 Free PE / Size 2559 / 10.00 GB VG UUID 3PwIMo-qXMx-l1SB-bXFX-8DWj-Ronu-N7BrIz
For this very first time we take all the space for our logical volume, so we use the size in extents, we will reduce or extend its size only when needed:
lvcreate --name home --extents 100%VG data
View our logical volume:
lvdisplay --- Logical volume --- LV Name /dev/data/home VG Name data LV UUID rgrcbQ-2eKj-w5tn-rxyA-RbDt-sGi1-egBHik LV Write Access read/write LV Status available # open 0 LV Size 10.00 GB Current LE 2559 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 254:0
Create the filesystem:
mkfs.ext3 /dev/data/home
copy our old home content to the new partition:
mkdir /tmp/home mount /dev/data/home /tmp/home cp -a /home/* /tmp/home/ umount /tmp/home
add our new home to /etc/fstab
:
/dev/data/home /home ext3 rw,noatime 0 0
and restart the server from gandi.net Web interface.
Web server (with SSL? TBD)
Change user properties if needed, for instance I put web data in /home/www-data so I do:
mkdir /home/www-data chown www-data:www-data /home/www-data usermod -d /home/www-data www-data usermod -s /bin/bash www-data
If needed change your DocumentRoot
in /etc/apache2/sites-enabled/000-default.
Backups
Gandi.net service conditions basically say that about data backups you are on your own, so you want to take good care and make full backups of your server by yourself.
You can use a script like this on your local machine:
#!/bin/sh # Make a full backup of a remote host with rsync when both the local and # remote root users are disabled. set -e set -x # We run rsync with sudo, but the local user who have access to the remote # server could be different from local root. So run ssh as the user specified # below in order to make it pick the key allowed to connect to the server. LOCAL_SSH_USER=local_user_who_can_access_the_remote_host # We require a remote user that is in sudoers (maybe in admin group), so we can # fetch every file on the server. REMOTE_SUDOER=remote_user_in_admin_group REMOTEHOST=192.0.2.1 # Exclude patterns, relative to the remote path given on command line EXCLUDE="--exclude '/proc' --exclude '/sys'" # Des destination dir on local host DESTDIR=/backups/root_example.com # Script starts here. # remember, we run the inner ssh as a local user LOCAL_SSH_CMD="sudo -u $LOCAL_SSH_USER ssh" REMOTEHOST="${REMOTE_SUDOER}@${REMOTEHOST}" # Use sudo on the remote side as well :) RSYNC="rsync -e \"$LOCAL_SSH_CMD\" --rsync-path=\"sudo rsync\"" # We run the rsync command as root also on the local host RSYNC="sudo $RSYNC -avz -H --progress --delete $EXCLUDE --delete-excluded" [ ! -d $DESTDIR ] && mkdir -p $DESTDIR eval $RSYNC $REMOTEHOST:/ $DESTDIR