You are not logged in.
Hello guys, I'd like to talk with you about creating a special custom LiveCD. I recently fell addicted with Porteus Linux for it's compact size and it's modularity. As I'm a Debian lover I tried to figure out how could I create a distro with that kind of features AND with my surprise I found what I've been looking for: Porteus-Wheezy and DebianDog. However as I'm curious guy I did not like to just to grab it and use it, so I decided to try to figure out how it was made and that's why I asked some questions here that I was able to solve:
Stripping down a debian netinstall (cli) to bare bones
Aufs, init and chroot
I've tried other distros in the meantime such as Linuxbbq Accademy and I'm going to get the best of every distro and include it in my LiveCD. I will be using Grub2 as bootloader because it's very useful to boot every kind of device, even if it takes a little more to boot up. Are you interested on my Project?
TO DO:
- Explain how to activate modules without rebooting the system (should be done with universal modules only)
- Update modules created on the previous tutorial (Done!)
- Explain live-boot mount points in a persistent environment and in a live-mode only
- Update offline guide
other stuff does not come into my mind..
DISCLAIMER:
This thread is still in development: the content of a single post can change very often during the day as I try to make this guide as good as possible. Keep in mind that everything that I show here can be followed at your own risk, I'm not responsible if you mess up your system, if your computer starts walking and thinking on it's own or if you end up with an unbootable LiveCD or LiveUSB.
TIP: These tutorials make a massive use of the terminal of the bash shell, therefore I encourage you to read the following books:
1, Debian Reference Guide (Chapter 1 GNU/Linux Tutorials)
2. Debian Reference Guide (Chapter 12.1 The shell script)
3. Advanced Bash-Scripting Guide
Credits:
- Fredx181, FoxyRoxyLinux and Saintless of the Puppy Linux Forum for DebianDog and it's scripts
- BrokenMan and Fanthom from the Porteus Forum for Porteus Linux
INDEX:
1.Build the basic LiveCD (Update)
2.Live USB Installation
3.Persistence
4. Module Creation
Last edited by Michele13 (2015-09-23 09:55:40)
Offline
Here are the steps that I made to make the core LiveCD, you will end up with a CLI system that is localized in your language
This part is based on l3net's Debian LiveCD tutorial
CHANGESLOG:
- Made the tutorial more tidy by making some structural changes and some corrections
- Added sound support
- Apt now does not install suggested or recommended package to save size
- Added wifi firmware
- Step 1: replaced genisoimage with xorriso, removed isolinux and syslinux and added grub-pc just to be sure you have it installed
- Step 4 added
- Stage 3 divided into more paragraphs to make the process easier to follow
- Made some corrections
- Reduced size of the ISO (more work could be done)
- made squashfs compression better
- created a locales modules
- made little corrections
- added brief instructions to update the system (tell me if you want me to describe the whole process in depth)
* small typo fixes
* man and manpages were added as packages to install manually since debootstrap no longer installs them by default in stretch/sid
* added warning about the possible change of name that network interfaces that have on the next debian releases
* added some other utils to be installed in the Live CD
Step 1- Installing the necessary software
Open a terminal and follow these instructions, keep in mind that every command preceeded by the # sign should be given as root, otherwise the dollar sign will be used. These are the software that you need to install on your system:
# apt-get install genisoimage debootstrap squashfs-tools grub-pc
Step 2 - Create a basic filesystem
Let's Create the skeleton of the project with
$ mkdir -p livecd/binary && cd livecd
# debootstrap stable chroot
the binary folder will contain the final LiveCD structure
Step 3 - Chroot
1. Enter in the system
Now it's time to chroot, to install packages and to finish to setup the LiveCD
# cd livecd
# chroot chroot
# mount none -t proc /proc
# mount none -t sysfs /sys
# mount none -t devpts /dev/pts
2. Update sources mirror
Edit the sources.list file with
nano /etc/apt/sources.list
and replace it's content with the following:
deb http://httpredir.debian.org/debian jessie main contrib non-free
#deb-src http://httpredir.debian.org/debian jessie main contrib non-free
deb http://httpredir.debian.org/debian jessie-updates main contrib non-free
#deb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free
deb http://security.debian.org/ jessie/updates main contrib non-free
#deb-src http://security.debian.org/ jessie/updates main contrib non-free
Save with CTRL+O and exit with CTRL+X, if you don't use CTRL+O you will be asked if you want to save the file when you exit.
3. Avoid installation of extra packages
Let's tell APT to not install suggested or recommended packages in order to save more space when we use the final system:
nano /etc/apt/apt.conf.d/99Recommends
where 99Recommends is a filename of choice, I suggest you to use a clever name
Apt::Install-Recommends "false";
Apt::Install-Suggests "false";
Note: you can install Recommends or Suggests by using "--install-recommends" or "--install-suggests" switches on apt-get while installing some packages. You can see Recommends or Suggests related to a package by using "apt-cache depends".
4. Set up networking
Change the hostname with:
echo "debian">/etc/hostname
and edit /etc/network/interfaces to make network working when you boot from the CD
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
Attention Please: in future versions of debian (like stretch/sid) the name of the network interfaces might change (eg. from eth0 to enp2s8) due to the new kernel, if your network does not work type ifconfig -a or ip link as root to see the network devices installed on your system. More info here
5. Update the system and installi other goodies
Update the system and install the core packages:
# apt-get update
# apt-get dist-upgrade
# apt-get --install-recommends install live-boot dbus linux-image-686-pae
Now for some utils:
# apt-get --install-recommends install grub-pc squashfs-tools aufs-tools man manpages zip unzip bzip2 xz-utils
WARNING: do not install grub on the MBR!
the sound:
# apt-get install --install-recommends alsa-base alsa-utils alsa-tools
let's install some firmwares (mostly non-free) in order to make wifi cards working without hassles
# apt-get --install-recommends install firmware-linux firmware-linux-free firmware-linux-nonfree firmware-b43-installer firmware-b43legacy-installer firmware-atheros firmware-brcm80211 firmware-intelwimax firmware-ipw2x00 firmware-iwlwifi firmware-libertas firmware-myricom firmware-netxen firmware-qlogic firmware-ralink firmware-realtek firmware-zd1211
6. Setting up Language and Regional Settings
Install locales package, change the keyboard layout and the timezone:
# apt-get --install-recommends install console-data keyboard-configuration tzdata
# dpkg-reconfigure locales console-data keyboard-configuration tzdata
(if you don't want localization simply leave locales as it is)
7. Exit from chroot
Set root password and do some cleanup:
# apt-get clean
# passwd
# umount /proc /dev/pts /sys
# rm -r /tmp/*
# rm /var/lib/apt/lists/*
# history -c
press CTRL-D to exit chroot
Step 4 - Building a locales module to save space on the final ISO (Optional)
Inside the $HOME/livecd directory create a folder for locales
# mkdir -p core_locales/usr/share/locales
# cp -r chroot/usr/share/locales/* core_locales/usr/share/locales/
# rm -r chroot/usr/share/locales/*
and then create a module called 000-core_locales.squashfs
# mksquashfs core_locales binary/live/000-core_locales.squashfs -b 1M -comp xz -Xbcj x86
Step 5 - Building the ISO
To build the ISO we will be using grub2 instead of syslinux because it's more useful and has a lot of features. Grub2 allows you not only to boot your LiveCD but even to boot up the system installed on the PC even if your MBR has been screwed up.
Move to your working directory and create some folders and files
$ cd livecd
$ mkdir -p binary/boot/grub/
$ mkdir binary/live/
$ touch binary/boot/grub/grub.cfg
Now let's copy the kernel with the initial ramdisk and make a squashfs filesystem. We will use TAB autocompletion here because the version of the kernel might change
# mv chroot/boot/vmlinuz-[TAB] binary/live/vmlinuz
# mv chroot/boot/initrd-[TAB] binary/live/initrd.img
# mksquashfs chroot binary/live/000-core.squashfs -b 1M -comp xz -Xbcj x86
Note: when the initrd looks inside the live directory of the LiveCD it will mount every file with the .squashfs extension that will find. This feature is the key that will make our debian bootable system behave like Porteus. If you don't feel comfortable about naming the compressed filesystem "000-filesystem.squashfs" use "filesystem.squashfs" instead.
Let's create the bootloader entries. Paste this inside the binary/boot/grub/grub.cfg
menuentry "Debian Jessie 8.0 (persistence)" {
linux /live/vmlinuz boot=live persistence
initrd /live/initrd.img
}
menuentry "Debian Jessie 8.0 (no persistence)" {
linux /live/vmlinuz boot=live
initrd /live/initrd.img
}
and finally let's create the ISO:
$ grub-mkrescue -o debian.iso binary/
Step 6 - Installing Updates
Recently Debian was updated to version 8.1. To install these updates enter inside chroot and mount the necessary filesystems (See step 3 pass 1), then run
# apt-get update
# apt-get dist-upgrade
Then exit the chroot and recreate the locale modules and the ISO by deleting the files inside the binary/live directory and recreating them (See Step 3 pass 7, Step 4 and Step 5).
Tell me if you want me to describe the whole process in depth. As always report any bugs
Enjoy
Last edited by Michele13 (2015-09-23 12:56:11)
Offline
if there's something that I missed you can tell it here. Why do we need to run
dbus-uuidgen > /var/lib/dbus/machine-id
while making the live cd? did I need to install headers? They are needed only for compiling software right?
Sorry If I'm making all these post in a single topic but this is to make everything polite...
EDIT:
In the next post I will talk about creating a LiveUSB using Grub2 and make enable persistence. Don't forget to test the ISO and report me errors, problems and suggestions.
Last edited by Michele13 (2015-05-27 13:04:05)
Offline
It's time to install our little system in our removable drive and to make it persistent!
EDIT: I've split the post in two to make things more easy and clear to follow. Persistence is a complex argument that deserves it's own post
CHANGESLOG:
- first draft (Incomplete)
- added more explanations about weird commands
- split the post in two. see next post for persistence
* completed section and made minor fixes to the structure of the article
Step 1 - Copy the system on the Removable Drive
Insert the disc of the system in the optical drive or mount the ISO using the terminal:
# mkdir /mnt/iso
# mount -o loop ./livecd/debian.iso /mnt/iso
Info: more informations about mounting devices can be found here
Insert your removable drive and using a file manager (or the terminal it's your choice) move to the location where you have mounted the ISO or the optical media. Copy all the content on your target device which must have a filesystem that is supported by grub2 (ext*/fat/ntfs/etc)
When you have finished with manipulating devices or files that are mounted remember to unmount them. Let's unmount the ISO with:
# umount /mnt/iso
Step 2 - Install Grub to MBR
now from a terminal let's install the bootloader on the MBR. but first we must know what is our device
# fdisk -l
which should print an output like this:
Disk /dev/sda: 60.0 GB, 60011642880 bytes
255 heads, 63 sectors/track, 7296 cylinders, total 117210240 sectors
Unit = sectors of 1 * 512 = 512 byte
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000762f2
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 73465855 36731904 83 Linux
/dev/sda2 93945856 115130367 10592256 7 HPFS/NTFS/exFAT
/dev/sda3 115132414 117209087 1038337 5 Esteso
/dev/sda4 73465856 93945855 10240000 83 Linux
/dev/sda5 115132416 117209087 1038336 82 Linux swap
Partition table entries are not in disk order
Disk /dev/sdb: 16.0 GB, 15999172608 bytes
255 heads, 63 sectors/track, 1945 cylinders, total 31248384 sectors
Unit = sectors of 1 * 512 = 512 byte
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000f1d56
Device Boot Start End Blocks Id System
/dev/sdb1 * 2048 31248383 15623168 b W95 FAT32
Now we know that the disk where we are going to install the MBR is /dev/sdb but where is the first partition mounted? This command should answer our question:
$ mount | grep -i /dev/sdb1 | cut -d " " -f3
which for me says:
/mnt/sdb1
Info:
The mount command, in this case, is used to display all devices mounted on the system. It's output is used as argument for another command (through a pipe), grep which scans the output of mount for each recurrence of the expression "/dev/sdb1"; finally the output of grep is passed to the cut command that divides the input in multiple portions for every occurrence of an empty space this occurrence is called delimiter and is set using the -d argoument. In this case I want to see what's between the third and the fourth occurrence of space character, which is the mount point of /dev/sdb1
Now Iet's run grub-install:
# grub-install --root-directory=/mnt/sdb1 /dev/sdb
Enjoy
Last edited by Michele13 (2015-05-29 10:25:36)
Offline
You: What is that strange command that you did?? Am I supposed to remember that long number? and what is dd??
dd --help
You could use "bs=1M", if it makes it any easier. It is usually recommended to do a sync afterwards, so add "&& sync" at the end of the command.
Last edited by damo (2015-05-28 11:42:15)
BunsenLabs Group on deviantArt
damo's gallery on deviantArt
Openbox themes
Forum Moderator
Offline
Michele13 wrote:You: What is that strange command that you did?? Am I supposed to remember that long number? and what is dd??
dd --help
![]()
You could use "bs=1M", if it makes it any easier. It is usually recommended to do a sync afterwards, so add "&& sync" at the end of the command.
Thanks for the report damo, I was going to explain the command that I used into an info box. I used bs=1000000 because I want the block size to be 1000KB instead of 1024 because today when we buy flash drives of a certain amount of Gigabytes the unit of size is NOT true Gigabyte which is 1024MB, but it's 1000MB! dd uses the correct way to calculate the size of a file, however a lot of software uses the correct way to calculate size. See here
Can you answer the question of the third post? I still did not get answer
Last edited by Michele13 (2015-05-28 13:15:22)
Offline
Let's finally talk about persistence. There are two type of persistence: the persistence on a file container and the persistence on partition
CHANGESLOG:
* first draft
Persistence file
let's create an empty file of the size of 1GB called "persistence" on our drive.
dd if=/dev/zero of=/mnt/sdb1/persistence bs=1000000 count=1000
You: What is that strange command that you did?? Am I supposed to remember that long number? and what is dd??
Answer: the dd command is a unix utility used to copy and convert files, we are creating a file full that contains nothing (in=/dev/zero) that is named "persistence" and is located in /mnt/sdb1 (of=/mnt/sdb1/persistence), to specify the unit of size of the file we are using the block size parameter, that is set to 1MB (1000000 bytes), and the count parameter; so we are creating a file composed by 1000 blocks of 1MB. (bs=1000000 count=1000).
Note: There are two definitions of Gigabyte, someone use the decimal definition (USB Storage Drive vendors) and others (some programs like dd) use the binary definition, we are going to use the decimal one. More info here
Now let's format this in ext4 without journaling.
# mkfs.ext4 -F /mnt/sdb1/persistence -O ^has_journal
mount it on a directory:
# mkdir /mnt/persistence
# mount -o loop /mnt/sdb1/persistence /mnt/persistence
and finally create a file named persistence.conf and unmount everything
# echo "/ union" > /mnt/persistence/persistence.conf
# umount /mnt/persistence
Persistence partition
This way is the more simple and allows you to allocate more than 4GB of space for persistence if you installed the system on a FAT32 partition.
Using your favorite partition tool (I suggests use GParted) resize the FAT32 partition in order to make some space to make a second ext4 partition labeled "persistence". Now let's disable the journaling.
Assuming that the persistence partition is /dev/sdb2 type in the terminal:
# tune2fs -O ^has_journal /dev/sdb2
Tip: You can check if your persistence partition or file has the journal activated by typing:
# dumpe2fs [TARGET] 2>/dev/null | grep -i has_journal
if it displays something you need it means that you need to disable it in order to extend your flash memory's life
Now mount the persistence partition and create a persistence.conf file inside it with thus content:
/ union
Good Luck
Last edited by Michele13 (2015-05-28 14:51:17)
Offline
Step 1- Installing the necessary software
[...]# apt-get install [...] grub-pc
This will remove grub-efi in UEFI systems and render them unable to upgrade to a new kernel version (specifically, it will stop the system from being able to update the GRUB configuration and I'm pretty sure APT will throw up an error and fail at that point).
You need to install locales as well before attempting to reconfigure it.
Last edited by Head_on_a_Stick (2015-05-28 18:48:04)
Offline
Michele13 wrote:Step 1- Installing the necessary software
[...]# apt-get install [...] grub-pc
This will remove grub-efi in UEFI systems and render them unable to upgrade to a new kernel version (specifically, it will stop the system from being able to update the GRUB configuration and I'm pretty sure APT will throw up an error and fail at that point).
You need to install locales as well before attempting to reconfigure it.
So what should I install instead of grub-pc?
Offline
So what should I install instead of grub-pc?
I have no idea -- this guide will only work for non-UEFI system at the moment.
In Arch, GRUB will install in either EFI or non-EFI systems depending on the flags passed. This is not possible in Debian as the EFI and non-EFI versions are split into two separate packages which are not co-installable.
I suggest you place a prominent warning at the top of the guide stating that this won't work for UEFI systems until you figure out how to make it work in such systems.
As far as I can tell, this guide will produce a live ISO with nothing on it except a command-line prompt and the GNU utilities: am I right or have I missed something here?
Offline
For Now it will provide a Live Iso with a grub2 bootloader, GNU Utils, non-free wireless firmwares, tools to use the aufs filesystem and squashfs but this will be expanded soon
Is there a way to use small headers to make subpararaphs like in HTML? I need them to split the third part of the first tutorial to make the Stage 3 more simple to follow
Offline
http://crunchbang.org/forums/help.php#bbcode
You really need to put a warning at the top for people with UEFI systems -- this guide will b0rk their machine as it stands at the moment.
Offline
I put a WARNING on the first topic so the reader will know the danger
Offline
^ Thank you
Offline
I'm glad you're showing that you're showing some support to this project instead of ignoring it, that would be sad for me as I'm doing a lot of work. I'm trying to make more tidy what I've wrote, correcting errors of syntax and other oversights. I'm writing the same guide on a HTML document to make it downloadable for everyone if you wish. Maintaining the HTML version can be hard, trough, as the white background and the black font made my eyes tired
Offline
@Michele13 I'm not ignoring this project and appreciate the work you're putting into it.
I'm just not qualified to make any comments. This is beyond my range of experience/ability.
There may be other forum members who feel the same, so don't be disappointed by a lack of comments.
John
--------------------
( a boring Japan blog , Japan Links, idle twitterings and GitStuff )
#! forum moderator BunsenLabs
Offline
The first part interests me. I was doing some homework on getting an arm install going this evening and figured out the rpi2 has no ability to boot from usb, nor does it have anything like a bios. As near as I can tell, I am going to need to do the whole debootstrap/chroot thing to get a basic install going, with the caveat that the rpi2 has some non-free firmware that will need to be pulled off of the rpi website. This looks to be the only way to get an arm build tracking debian instead of raspberry pi's repositories. I am going to work on this part and see if I can get a basic command line system up. If so, then the BunsenLabs netinstall script would need to be modified to track armhf repositories. I don't see the point of a Live Build however, unless there are other arm boards out there that can boot via usb.
I will work on this as I get time and I think Michele's tutorial in the first part should get me moving on the debootstrap/chroot portion of things.
Offline
I finished to write the single page HTML version of this tutorial to download and read offline!
It will be updated as new parts will come out
EDIT: the Google Drive folder dedicated to the project can be found here
User: root
Password: toor
I successfully built some modules, in the next posts I will show you how I did it.
Last edited by Michele13 (2015-08-12 18:12:22)
Offline
Would you rather have a smaller ISO or one that has man, docs and locales built in?
Offline
Would you rather have a smaller ISO or one that has man, docs and locales built in?
Please leave the man pages in, I'm completely lost without them.
As for locales: surely everyone speaks English so that's all you need, right?
]:D 8o
Offline
Michele13 wrote:Would you rather have a smaller ISO or one that has man, docs and locales built in?
Please leave the man pages in, I'm completely lost without them.
As for locales: surely everyone speaks English so that's all you need, right?
]:D 8o
Sorry I only speak American {)
If you can't sit by a cozy fire with your code in hand enjoying its simplicity and clarity, it needs more work. --Carlos Torres
I am a #! forum moderator. Feel free to send me a PM with any question you have!
Offline
^ "I only speak two languages - English, and bad English!"
Offline
I think that man pages should be left too, I will place locales page in a separate module, can the locales directory's content be deleted safely without damaging English localization?
Offline
CHANGESLOG:
- first draft
- made better description of universal modules and system related modules (thanks saintless)
* fixed mksquashfs command arguments
* fixed xorg minimal installation
there are two types of modules:
- the universal module: Safe for dpkg database module (it will probbaly not work on different system which has some dependencies missing compared to the system the module was made, but it will not break dpkg database (var/lib/dpkg) because the important files are renamed and do not overwrite the existing /var/lib/dpkg/status, available and info files).
- the system related module: Dangerous for different system module and better do not share it (it might or might not work on different system, but it will break dpkg database with sure changing the information about the installed packages listed in /var/lib/dpkg/status and available files). Next time you try to install some package with such system related (dangerous) module you will have broken dpkg (apt-get). If it is live system it will break only your save file content, but you have to start with fresh save file reproducing all the changes again.
If you're going to create a module of big dimensions I suggest you to use a big ext* partition or a persistence file.
To build the module we are goint to use the AUFS filesystem (and hopefully learn how it works).
AUFS (Another Union FileSystem) is a special filesystem that merges the content of many directories into one. This technology is used to make LiveCD work, infact inside the initial ramdisk the init script that is executed mounts a read only filesystem and, using aufs it is merged with another directory that is mounted with a temporary filesystem (tmpfs) stored in RAM.
Important: AUFS can't merge two folders if they reside inside an aufs filesystem. Make sure that the one directory does not reside inside the aufs root.
Create a working folder inside your storage mount point (eg /tmp/xorg) move into it and create two directories called target and union.
let's merge the 000-filesystem.squashfs file that is mounted (read only) on /lib/live/mount/rootfs/000-filesystem.squashfs/ and a writable directory (/tmp/xorg/target/)
# mount -t aufs -o br=/tmp/xorg/target:/lib/live/mount/rootfs/000-filesystem.squashfs/ none /tmp/xorg/union
let's chroot into it and mount proc, sys and devpts.
# chroot target
# mount -t proc none /proc
# mount -t sysfs none /sys
# mount -t devpts none /dev/pts
Make sure that internet is working inside the chroot, if it does exit the chroot and type:
# cp /etc/resolv.conf target/etc/
# xhost +local:
Now let's begin. In this tutorial we are creating an Xorg module, which can be installed in the usual way, recommended if you're a beginner (install xorg), or using in it's minimal but still perfectly functional form (install xserver-xorg, xinit and x11-xserver-utils)
Inside the chroot type:
# apt-get update
# apt-get install xserver-xorg xinit x11-xserver-utils
When you've finished give these commands to exit the chroot and partially clean the system:
# apt-get clean
# umount /proc /dev/pts /sys
# history -c
(Press CTRL+D)
# umount union
(if it fails try unmount -l union)
This prevented avoided to include some garbage inside your module, however the cleanup process is not completed. Move into the target directory, we are going to delete a lot of specific system files that may prevent the new module to work well.
# rm target/var/lib/apt/lists/*
# rm target/etc/resolv.conf
# rm target/etc/menu.old
# rm target/var/lib/alsa/asound.state
# rm target/root/.bash_history
# rm target/root/.xsession-errors
# rm -rf target/root/.cache
# rm -rf target/root/.thumbnails
# rm -rf target/tmp/*
# rm -rf target/var/cache
# rm -rf target/var/log
# rm -rf target/.unionfs
# rm target/etc/blkid-cache
# rm target/etc/udev/rules.d/70-persistent*
# rm target/var/lib/dhcp/dhclient.eth0.leases
# rm target/var/lib/dhcpcd/*.lease
# rm -r target/.wh*
to make the module universal you must move two files with these commands:
# mv target/var/lib/dpkg/info target/var/lib/dpkg/infonew
# mv target/var/lib/dpkg/status target/var/lib/dpkg/statusnew
# mv target/var/lib/dpkg/available target/var/lib/dpkg/availablenew
Now you can squashfs the module with
# mksquashfs target [name of module] -b 1048576 -comp xz -Xbcj x86
and put it on the live folder of your boot media. Choose name that allows the module to be loaded after the last one that you created, this is useful with system related modules so your system won't be screwed up.
Enjoy! Report me any bugs!
Last edited by Michele13 (2015-06-04 15:05:23)
Offline
Keep on with the great work michele13.
Thanks.
Offline
Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.
Server: acrobat