Cómo crear un servidor web casero con Odroid-U3 y Gentoo

  • #linux

En este extenso pero completo tutorial te explicamos como instalar Gentoo y todo lo necesario para convertir tu Odroid-U3 en un servidor web.

Odroid-U3 es un ordenador de placa reducida tipo Raspberry Pi pero bastante más potente. Fabricado por Hardkernel cuenta con un Samsung Exynos 4412 Prime Cortex-A9 Quad Core 1.7Ghz, el mismo que monta el Samsung Galaxy S3. A esto se le suman 2 GB de memoria RAM, conector HDMI 1080p, Ethernet RJ-45 10/100 Mbit, entrada y salida de audio, 3 puertos USB, puertos GPIO, UART y SPI, y unas cuantas cosas más que os dejo que consultéis en su página web oficial. Lo que a nosotros nos importa es que tiene una CPU basada en ARM bastante potente y es compatible con cualquier distribución Linux (¡también Android 4.x!).

Odroid-U3, un micro ordenador capaz de realizar tareas de servidor

Apenas ocupa lo mismo que una tarjeta de crédito y su consumo es realmente bajo. Al correr sobre Linux, podemos instalar Node.js, MySQL, MongoDB (soporte ARM muy alpha), FTP, Samba y un sin fin de servicios que hacen de este Micro PC el servidor casero perfecto.

Más información sobre Odroid-U3 en su página oficial.

Sobre Gentoo

¿Porqué Gentoo para un servidor web? Muy sencillo: siempre lo he utilizado y siempre me ha gustado. Amo portage y emerge. Además, más vale lo bueno conocido... (era así, ¿no?).

Ni que decir queda que si os gusta el Odroid-U3, podéis instalar Ubuntu o lo que queráis.

Instalando Gentoo en el Odroid-U3

Necesitaremos un ordenador con Linux para instalar Gentoo en Odroid (sirve una distribución Live CD, en nuestro caso utilizamos Ubuntu).

Algunos comandos necesitan permisos de administrador, entra como root o utiliza sudo.

Por si acaso alguien se da cuenta, algunos comandos o ficheros hacen referencia al Odroid-U2. No pasa nada, sirven para el U3 también y son oficiales.

Lo primero de todo, vamos a crear una carpeta donde trabajaremos:

cd ~
mkdir gentoo
cd gentoo

Descargando lo necesario

Descargamos el bootloader (podemos compilarlo nosotros mismos pero como no cambia nada usaremos uno compilado):

wget http://odroid.in/guides/ubuntu-lfs/boot.tar.gz

Descargamos mediante elinks o cualquier otro navegador el último stage 3 ARM de la siguiente dirección:

elinks http://gentoo-euetib.upc.es/mirror/gentoo/releases/arm/autobuilds/current-stage3-armv7a_hardfp/

También un snapshot de Portage:

wget http://gentoo-euetib.upc.es/mirror/gentoo/snapshots/portage-latest.tar.xz

Instalamos las herramientas de u-boot para poder utilizar mkimage y así crear el archivo boot.scr. Podemos hacerlo mediante Ubuntu o Gentoo:

apt-get install u-boot-tools # Ubuntu
emerge u-boot-tools # Gentoo

Preparando la tarjeta de memoria

Recordad cambiar /dev/sdX por la ruta donde se encuentre vuestra tarjeta de memoria.

Formateamos nuestra tarjeta eMMC:

dd if=/dev/zero of=/dev/sdX bs=1M

Descomprimimos e instalamos el bootloader:

tar -zxvf boot.tar.xz
cd boot
chmod +x sd_fusing.sh
./sd_fusing.sh /dev/sdX
cd ..

Usaremos dos tablas de particiones, una para el kernel y la otra para rootfs. La primera es FAT32 y la segunda ext4 sin journaling y con noatime como opciones de montaje. Las creamos utilizando fdisk:

fdisk /dev/sdX
n
p
1
3072
+64M
n
p
2
134114
<pulsa intro>
t
1
c
w

Si no entendéis el significado de esto podéis consultar la documentación de fdisk, pero básicamente crea 2 particiones: una FAT32 de 64 MB para el kernel y otra ext4 con el resto del espacio disponible. Algo importante es dejar 3072 bytes libres antes de la primera partición, ya que este espacio lo ocupa el bootloader.

Ejecutamos el siguiente comando para que el kernel lea la nueva tabla de particiones (si tu sistema no posee dicho comando, lo encontrarás en el paquete parted):

partprobe

Recuerda que ahora tenemos /dev/sdX1 y /dev/sdX2 que debemos sustituir por nuestras particiones.

Damos formato a las particiones, cambiamos el UUID de nuestra partición rootfs y desactivamos el journaling para liberar algo de carga a la tarjeta:

mkfs.vfat -n boot /dev/sdX1
mkfs.ext4 -L rootfs /dev/sdX2
tune2fs /dev/sdX2 -U e139ce78-9841-40fe-8823-96a304a09859
tune2fs -O ^has_journal /dev/sdX2

Instalando el sistema base

Comenzamos montando las particiones:

mkdir rootfs
mkdir boot
sudo mount /dev/sdX1 boot
sudo mount /dev/sdX2 rootfs

Instalamos el stage 3 en nuestro rootfs:

tar -xvjpf stage3-*.tar.bz2 rootfs

Y después la snapshot de Portage:

tar -Jxvf portage-latest.tar.xz rootfs/usr

Opción 1: Instalando el kernel precompilado (recomendado)

Descargamos, descomprimimos y movemos los archivos. En la carpeta boot debería haber dos ficheros tras descomprimir:

wget http://builder.mdrjr.net/kernel-3.8/00-LATEST/odroidu2.tar.xz
tar -Jxvf odroidu2.tar.xz
mv lib rootfs
mv usr rootfs

Opción 2: Compilando el kernel (para expertos)

Para compilar el kernel tenemos que instalar las toolchain para poder compilar código para ARM desde nuestra arquitectura x86:

wget http://odroid.in/guides/ubuntu-lfs/arm-unknown-linux-gnueabi.tar.xz
tar -Jxf arm-unknown-linux-gnueabi.tar.xz

Clonamos las fuentes del kernel:

git clone --depth 0 https://github.com/hardkernel/linux.git -b odroid-3.8.y odroid-3.8.y

Preparamos la compilación:

cd odroid-3.8.y
export ARCH=arm
export CROSS_COMPILE=../arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-
make odroidu2_defconfig

Pasamos a compilar (el número 4 es el número de núcleos de tu procesador):

make -j4

Lo último es instalar el kernel y los módulos:

cp arch/arm/boot/zImage ../boot
make ARCH=arm INSTALL_MOD_PATH=../rootfs modules_install
cd ..

Creando el boot script

Si ya elegiste el kernel precompilado o lo compilaste tú mismo, el siguiente paso antes de darle vida a nuestro servidor es crear un necesario script de arranque. Lo mostramos en bloques distintos para que copies y pegues los comandos más fácilmente.

cd boot

En el siguiente comando, tal vez necesites añadir sudo al comando tee (sudo tee boot.txt), depende de si eres administrador o no. Todo el bloque en sí es el mismo comando, así que puedes copiar y pegar todo de golpe (por si no conoces la sintaxis heredoc).

cat << __EOF__ | tee boot.txt
setenv initrd_high "0xffffffff"
setenv fdt_high "0xffffffff"
setenv bootcmd "fatload mmc 0:1 0x40008000 zImage; bootm 0x40008000"
setenv bootargs "console=tty1 console=ttySAC1,115200n8 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw mem=2047M"
boot
__EOF__

Por norma general nuestra tarjeta eMMC será llamada /dev/mmcblk0p2 una vez arranque el sistema, pero si insertamos una tarjeta SD esto puede ocasionar problemas en el arranque debido al orden. En cuyo caso tendréis que volver a compilar la imagen boot.scr y copiarla de nuevo a la tarjeta eMMC, cambiando el valor anterior por /dev/mmcblk1p2 (posiblemente, puede variar). Yo usaré una tarjeta SD desde el principio por lo tanto ya he cambiado la variable root a /dev/mmcblk1p2.

Compilamos nuestro script y volvemos atrás:

mkimage -A arm -T script -C none -n boot -d ./boot.txt boot.scr
cd ..

Quien avisa no es traidor (¿opcional?)

Los primeros intentos de arranque fueron un completo dolor de cabeza ya que algunas cosas no funcionaban como esperaba y tenía que volver a conectar la tarjeta eMMC al ordenador una y otra vez para solucionarlas desde Linux. Voy a detallarlas para ahorraros tiempo, total, no hacen daño a nadie.

La contraseña de root

Yo no sabía la contraseña de root, no se vosotros. Así que esto podemos solucionarlo ahora mismo. Editamos el fichero shadow y veremos que hay una cadena parecida a esta:

rootfs/etc/shadow
root:$X$SK5xfLB1ZW:0:0...

Tenemos que editarla y eliminar el segundo "parámetro" que corresponde a la contraseña, para que quede algo así:

rootfs/etc/shadow
root::0:0...

Cuando arranquemos nuestro Odroid la próxima vez, usaremos passwd para generar una nueva contraseña.

El servicio SSH

Aseguraos de que el servicio SSH va a funcionar al arrancar, sobre todo si no vais a conectar un teclado/pantalla. Debería existir un enlace en rootfs/etc/runlevels/default. Si no, lo creáis:

ln -sf rootfs/etc/init.d/sshd rootfs/etc/runlevels/default

La conexión de red

En nuestro caso utilizamos IP estática para conectar con el router, por lo que no tendremos conexión hasta que editemos el fichero net.eth0 con lo siguiente:

rootfs/etc/conf.d/net.eth0
config_eth0="10.0.0.2 netmask 255.255.255.0"
routes_eth0="default via 10.0.0.1"
dns_servers_eth0="8.8.8.8 8.8.4.4"

¡Acordaos de cambiar los datos por los vuestros! También hay que crear el script de inicio para eth0, que por defecto no suele existir:

ln -s rootfs/etc/init.d/net.lo rootfs/etc/init.d/net.eth0

Si usáis DHCP o Wi-Fi, ya sabéis que debéis usar otra configuración.

Y esos son los briconsejos de hoy.

Arrancando Odroid-U3 por primera vez

Salimos y nos preparamos para iniciar el sistema:

umount boot
umount rootfs
sync

Arrancamos el Odroid y si todo ha ido bien pasamos al siguiente capítulo.

Configurando Gentoo en el Odroid-U3

Ahora es el momento de configurar el sistema base, algo que a pesar de que está en el magnífico handbook de Gentoo, haré referencia aquí.

Configuración básica

Editamos el fichero make.conf con nuestras opciones. A modo de ejemplo y sin que sirva de precedente, comparto el mío (lo único que no debéis cambiar son las cuatro primeras variables):

/etc/portage/make.conf
CFLAGS="-O2 -pipe -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard"
CXXFLAGS="${CFLAGS}"
CHOST="armv7a-hardfloat-linux-gnueabi"
MAKEOPTS="-j4"

USE="-bindist -gtk -X -sdl -alsa -cups threads fpm"

GENTOO_MIRRORS="http://mirror.qubenet.net/mirror/gentoo/ http://mirror.ovh.net/gentoo-distfiles/"

NGINX_MODULES_HTTP="access auth_basic autoindex browser charset empty_gif fastcgi flv geo geoip gzip gzip_static limit_conn limit_req limit_zone map memcached mp4 proxy referer rewrite scgi split_clients ssi upload_progress upstream_ip_hash userid uwsgi"

PHP_INI_VERSION="production"

PHP_TARGETS="php5-5"

PORTDIR="/usr/portage"
DISTDIR="${PORTDIR}/distfiles"
PKGDIR="${PORTDIR}/packages"

Sincronizamos emerge y actualizamos si fuera necesario:

emerge --sync

Editamos el fichero fstab. En nuestro caso utilizamos una tarjeta SD a modo de almacenamiento extra, por lo que nuestra tarjeta SD está en /dev/mmcblk0p1 y nuestro rootfs se encuentra en /dev/mmcblk1p1 (si no utilizáis tarjeta SD tenéis que adaptar las líneas):

/etc/fstab
/dev/mmcblk1p1          /media/boot             vfat            defaults,rw,owner,flush,umask=000       0 0
UUID=e139ce78-9841-40fe-8823-96a304a09859               /               ext4            errors=remount-ro,noatime               0 1
/dev/mmcblk0p1          /media/sdcard             ext4            defaults,noatime       0 0

A continuación montamos la partición del kernel (así podremos actualizarlo en el futuro):

mkdir -p /media/boot
mount /media/boot

Configuración extendida

Los siguientes pasos son opcionales, puedes saltarte los comandos que quieras o pedir más información abajo en los comentarios. Estos son algunos de los que he usado y los comparto para facilitarlos la configuración:

echo "Europe/Madrid" > /etc/timezone
emerge --config sys-libs/timezone-data

/etc/locale.gen
es_ES.UTF-8 UTF-8
es_ES ISO-8859-1
es_ES@euro ISO-8859-15
en_US.UTF-8 UTF-8
en_US ISO-8859-1
locale-gen

/etc/conf.d/hostname
hostname="odroid"

emerge syslog-ng cronie gentoolkit ntp logrotate eix mlocate u-boot-tools git
rc-update add net.eth0 default
rc-update add sshd default
rc-update add syslog-ng default
rc-update add cronie default
rc-update add ntp-client default
rc-update add ntpd default

/etc/portage/package.accept_keywords
www-servers/nginx ~arm
net-libs/nodejs ~arm

/etc/portage/package.use
dev-lang/php curl gd mysqli truetype zip

emerge mysql php nodejs nginx
rc-update add nginx default
rc-update add php-fpm default
rc-update add mysql default

emerge zip lynx mytop iotop

eselect python list # Seleccionamos Python 2.x con eselect python set

npm install -g bower
npm install -g pm2

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

Todo un éxito

Ya está, ya tenemos instalado nuestro servidor web con nginx, Node.js, PHP y MySQL funcionando. Todo en el tamaño de una tarjeta de crédito y con un consumo ridículo. Espero que os animéis y montéis un servidor casero de este tipo para desarrollo web porque merece mucho la pena todo lo que facilita el trabajo y todas las ventajas que supone tener el servidor web separado de nuestro ordenador. Más seguro y fiable.

Agradecimientos a mdrjr de la comunidad Odroid por su gran ayuda y sus grandes aportes a la comunidad.

Compartir en