Renovar certificado Let’s Encrypt en Alpine

Recientemente me ha sucedido que caducó el certificado de Let’s Encrypt que tenía de un dominio. En problema es que el Nginx al que apunta dicho dominio estaba dockerizado en un Alpine así que he tenido que buscar cómo actualizarlo.

Y la cosa no puede ser más sencilla.

Accedemos a una shell de nuestro contenedor. En mi caso:

docker exec -it nginx sh

Instamos Cerbot con su plugin para Nginx:

/ # apk update
/ # apk add certbot-nginx

Hacemos una prueba sin aplicar cambios:

/ # certbot renew --dry-run
(...)
Congratulations, all renewals succeeded:
/etc/letsencrypt/live/dominio1.es/fullchain.pem (success)
/etc/letsencrypt/live/dominio2.com/fullchain.pem (success)

Y si todo va bien ya solo tenemos que repetir el comando anterior pero sin el –dry-run.

Pi-hole dockerizado

En esta guía voy a explicar cómo instalar Pi-hole dockerizado en una Raspberry Pi con DietPi y Docker Compose.

NOTA: es probable que estas instrucciones sean válidas para otras distribuciones Linux.

Internet está llena de guías como ésta. En mi caso, para mantener la guía lo más sencilla posible asumo que:

  • Ya tenemos la Raspberry Pi con DietPi instalado y funcional.
  • La Raspberry Pi tiene IP fija.
  • La Raspberry Pi NO es accesible desde Internet. Solo accederemos a ella desde nuestra red local.
  • Solo vamos a acceder al entorno gráfico de Pi-hole vía HTTP. Nada de HTTPS.
  • No vamos a usar el servidor DHCP de Pi-hole.

Lo primero de todo es crear y acceder a una carpeta para el docker-compose.yaml:

dietpi@miraspberrypi:~$ mkdir -p ~/.docker-compose/pihole
dietpi@miraspberrypi:~$ cd ~/.docker-compose/pihole
dietpi@miraspberrypi:~/.docker-compose/pihole$

Ahí creamos el fichero docker-compose.yaml con el siguiente contenido:

version: "3"
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "8080:80/tcp"
    environment:
      TZ: 'Europe/Madrid'
      WEBPASSWORD: 'contraseña'    
    volumes:
      - '/home/dietpi/.docker/pihole/etc-pihole/:/etc/pihole/'
      - '/home/dietpi/.docker/pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/'    
    restart: unless-stopped

Del fichero anterior ajustar:

  • Cambiar 8080 por el puerto que queramos usar para conectarnos al entorno gráfico de Pi-hole. O dejarlo así si nos gusta ese 🙂
  • Cambiar ‘Europe/Madrid’ por tu zona horaria.
  • Cambiar ‘contraseña’ por la contraseña que usaremos para conectarnos al entorno gráfico de Pi-hole.

Una vez nuestro fichero esté listo ya solo tenemos que levantar el contenedor:

dietpi@miraspberrypi:~/.docker-compose/pihole$ docker-compose up -d
Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
Creating network "pihole_default" with the default driver
Pulling pihole (pihole/pihole:latest)...
latest: Pulling from pihole/pihole
9159b6bb9431: Pull complete
9b9b713af3af: Pull complete
8be7a40021ce: Pull complete
55c2b086451c: Pull complete
eb774076c2a1: Pull complete
2bafdf4926be: Pull complete
f09a3462cef2: Pull complete
33df9ce656ad: Pull complete
Digest: sha256:6a633b5b2b4a9f343aa01101c89ebba36aa90003df0e379d2e702e0372ed9712
Status: Downloaded newer image for pihole/pihole:latest
Creating pihole ... done
dietpi@miraspberrypi:~/.docker-compose/pihole$

¡Y listo! Ya tenemos nuestro Pi-hole corriendo:

dietpi@miraspberrypi:~/.docker-compose/pihole$ docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS                    PORTS                                                                           NAMES
73244e306142   pihole/pihole:latest               "/s6-init"               14 minutes ago   Up 14 minutes (healthy)   0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp, 67/udp, 443/tcp, 0.0.0.0:8080->80/tcp   pihole
dietpi@miraspberrypi:~/.docker-compose/pihole$

Ya solo nos quedaría configurar nuestro router para que el use la Raspberry Pi como servidor DNS.

Si queremos acceder al entorno gráfico podemos hacerlo a través de la URL:

http://IP_RASPBERRY:8080/admin

Docker Compose en DietPi

Podemos instalar Docker Compose en DietPi usando el gestor de paquetes pip.

Para ello primero hemos de instalar pip y sus dependencias:

sudo apt -y install libffi-dev libssl-dev python3-dev python3 python3-pip python3-setuptools

Después ejecutamos el siguiente comando para instalar Docker Compose:

sudo pip3 install docker-compose

Y listo 🙂

Nota: a día de hoy (28-01-2021), durante la instalación aparece un error. Sin embargo, Docker Compose queda instalado y funcionando. Pego el error en cuestión:

usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
     or: -c --help [cmd1 cmd2 ...]
     or: -c --help-commands
     or: -c cmd --help

  error: invalid command 'bdist_wheel'

  ----------------------------------------
  Failed building wheel for pyrsistent
  Running setup.py clean for pyrsistent
Successfully built PyYAML
Failed to build pyrsistent

Transmission en DietPi/Raspberry Pi OS

Instalar Transmission Daemon en DietPi/Raspberry Pi OS es muy sencillo. Ya sea a la vieja usanza (sudo apt -y install transmission-daemon) o con los scripts de DietPi (sudo dietpi-software).

Sin embargo, en ambos casos nos encontraremos con que el demonio de Transmission corre con usuario debian-transmission:

dietpi@miraspberrypi:~$ ps -ef | grep transmission
debian-+ 504 1 0 ene17 ? 00:00:46 /usr/bin/transmission-daemon -f --log-error
dietpi 19488 10078 0 12:53 pts/0 00:00:00 grep transmission

Para que Transmission corra con usuario dietpi/pi (o cualquier otro usuario) debemos seguir los siguientes pasos:

Creamos el nuevo directorio para la configuración de Transmission:

dietpi@miraspberrypi:~$ mkdir ~/.transmission

Detenemos Tranmission:

dietpi@miraspberrypi:~$ sudo systemctl stop transmission-daemon

Editamos el fichero de gestión del servicio:

dietpi@miraspberrypi:~$ sudo vi /lib/systemd/system/transmission-daemon.service

Y aplicamos los siguientes cambios:

[Unit]
Description=Transmission BitTorrent Daemon
After=network.target

[Service]
User=dietpi/pi (elige uno)
Type=notify
ExecStart=/usr/bin/transmission-daemon -f --log-error -g /home/dietpi/.transmission
ExecStop=/bin/kill -s STOP $MAINPID
ExecReload=/bin/kill -s HUP $MAINPID

[Install]
WantedBy=multi-user.targe

Recargamos la configuración de systemd y arrancamos Tramission:

dietpi@miraspberrypi:~$ sudo systemctl daemon-reload
dietpi@miraspberrypi:~$ sudo systemctl start transmission-daemon

En el nuevo directorio de configuración ya aparecerán los ficheros de configuración de Transmission:

dietpi@miraspberrypi:~$ ll .transmission/
total 16K
drwxr-xr-x 2 dietpi dietpi 4,0K ene 18 13:52 blocklists
drwxr-xr-x 2 dietpi dietpi 4,0K ene 18 13:52 resume
-rw------- 1 dietpi dietpi 2,2K ene 18 13:52 settings.json
drwxr-xr-x 2 dietpi dietpi 4,0K ene 18 13:52 torrents

Y eso es todo. Recuerda que has de detener Transmission antes de hacer ningún cambio en el settings.json.

DietPi: escritorio con usuario no root

De un tiempo a esta parte vengo usando DietPi en lugar de Raspberry Pi OS y me encanta. Partes con un S.O. mínimo y a partir de ahí tú has de instalar lo que necesites bien a mano o bien mediante su muy completo menú.

En mi caso he optado por instalar el escritorio con Mate y me he encontrado con el problema de que solo el usuario root es capaz de arrancar el entorno gráfico.

Para poder arrancar el entorno gráfico con usuario dietpi es necesario ejecutar el siguiente comando:

sudo usermod -a -G adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,gpio,i2c,spi dietpi

Yo, además, una vez instalado el S.O., desenchufo la Raspberry Pi del monitor pero quiero poder seguir conectándome al escritorio vía VNC. Para que se siga iniciando el entorno gráfico aunque no haya ningún monitor conectado hago el siguiente cambio:

Fichero: /boot/config.txt

#-------Display---------
# If you get no picture, set the following to "1" to apply most compatible HDMI settings.
hdmi_safe=1

Fail2ban para Emby Server

Aunque tengo Emby instalado en otra máquina con Lubuntu, no en la Raspberry Pi, hago este post porque me ha costado un rato configurar Fail2ban para Emby.

Lo primero es crear el filtro:

vi /etc/fail2ban/filter.d/emby.conf

Con el siguiente contenido:

# Fail2Ban filter for emby
#

[INCLUDES]
before = common.conf

[Definition]

_daemon = emby-server

failregex = Info HttpServer: HTTP Response 401 to <HOST>.*authenticatebyname

Luego añadimos las siguientes líneas a nuestro /etc/fail2ban/jail.local:

[emby]
enabled = true
port = 8920
filter = emby
logpath = /var/lib/emby-server/logs/server-*.txt

Ya solo nos queda recargar Fail2ban:

service fail2ban reload

Y comprobamos como está nuestra jaula:

# fail2ban-client status emby
Status for the jail: emby
|- Filter
|  |- Currently failed:    0
|  |- Total failed:    0
|  `- File list:   /var/lib/emby-server/logs/server-63625478399.txt
`- Actions
   |- Currently banned:    0
   |- Total banned:    0
   `- Banned IP list:

Basado en la información encontrada en este post.

Tuneando Nextcloud

Hace tiempo escribí un post sobre cómo instalar Nextcloud en Lighttpd. Resulta que hoy he tenido que repetir la instalación y, si bien el proceso en sí fue muy sencillo siguiendo esas instrucciones, me ha llevado un buen rato el tunearlo.

Dados los limitados recursos de la Raspberry Pi, cualquier tuneo que nos permita mejorar un poco el rendimiento es bienvenido así que allá vamos.

Sistema de bloqueo de ficheros con Redis

Por defecto, Nextcloud utiliza la base de datos para el bloqueo de ficheros. Si utilizamos un servidor Redis para este cometido liberaremos mucha carga del MariaDB.

Instalar y configurar Redis

Instalamos:

sudo apt install redis-server php-redis

Editamos el fichero de configuración de Redis:

sudo vi /etc/redis/redis.conf

Y establecemos los siguientes valores:

unixsocket /var/run/redis/redis.sock
unixsocketperm 770
port 0
requirepass micontraseña

Añadimos el usuario de Lighttpd al grupo redis:

usermod -a -G redis www-data

Reiniciamos Redis:

sudo service redis-server restart

Configurar Nextcloud

Añadimos los siguientes parámetros a nuestro config.php:

 'filelocking.enabled' => true,
 'memcache.locking' => '\\OC\Memcache\\Redis',
 'redis' => array(
    'host' => '/var/run/redis/redis.sock',
    'port' => 0,
    'dbindex' => 0,
    'password' => 'micontraseña',
    'timeout' => 1.5,
    ),

Y reiniciamos Lighttpd:

service lighttpd restart

En este punto debería funcionar todo pero he de decir que en mi caso aparecían errores de conexión al Redis en los logs de Lighttpd y Nextcloud. Todo se solucionó con un reinicio de la Raspberry Pi.

Redis para data caching

Utilizando un sistema de data caching lo que hacemos es que los objetos solicitados con más frecuencia se guarden en memoria para servirlos mucho más rápido.

En nuestro caso, dado que ya tenemos el Redis instalado y funcionando, sólo tenemos que añadir el siguiente parámetro a nuestro config.php:

'memcache.local' => '\OC\Memcache\Redis',

Certificado SSL gratuito para montar tu servidor seguro con Lighttpd

Tal y como reza su eslogan, Let’s Encrypt es una entidad certificadora gratuita, automatizada y abierta.

En este artículo contaré cómo instalar un certificado SSL de Let’s Encrypt en nuestro servidor Lighttpd y cómo forzar que todo el tráfico vaya por HTTPS.

Instalar acme.sh

acme.sh es un script para gestionar los certificados gratuitos de Let’s Encrypt.

Primero instalamos las dependencias:

sudo apt install git bc wget curl

Clonamos el repositorio:

git clone https://github.com/Neilpang/acme.sh.git

E instalamos:

cd acme.sh/
sudo -i
./acme.sh --install

Este último comando tiene que haber copiado ~/.bashrc el siguiente script de carga de variables:

. "$HOME/.acme.sh/acme.sh.env"

Cargamos las nueva variables:

source ~/.bashrc

Pasos previos

Crear el directorio .well-known/acme-challenge/

Ejecutar los siguientes comandos ajustando la variable D a nuestra ruta raíz del contenido web y el usuario www-data si fuera necesario:

D=/var/www/html
mkdir -vp ${D}/.well-known/acme-challenge/
###---[ NOTA: Adjustar el usuario si no es www-data ]---###
chown -R www-data:www-data ${D}/.well-known/acme-challenge/
chmod -R 0555 ${D}/.well-known/acme-challenge/

Crear la ruta para guardar el certificado

mkdir -p /etc/lighttpd/ssl/midominio.com/

Generar el fichero dhparams.pem

cd /etc/lighttpd/ssl/midominio.com/
openssl dhparam -out dhparams.pem -dsaparam 4096

Obtener certificado

Ejecutamos ajustando la ruta raíz y el dominio:

acme.sh --issue -w /var/www/html/ -d midominio.com

Configurar Lighttpd

Habilitamos el SSL:

lighty-enable-mod ssl

Y editamos el fichero de configuración correspondiente:

vi /etc/lighttpd/conf-enabled/10-ssl.conf

Debe quedar similar a éste pero ajustando las rutas:

### Todo por https
$HTTP["scheme"] == "http" {
 # capture vhost name with regex conditiona -> %0 in redirect pattern
 # must be the most inner block to the redirect rule
 $HTTP["host"] =~ ".*" {
 url.redirect = (".*" => "https://%0$0")
 }
}
### Fin todo por https

$SERVER["socket"] == "0.0.0.0:443" {
 ssl.engine = "enable"
 ssl.disable-client-renegotiation = "enable"

 ssl.pemfile = "/etc/lighttpd/ssl/midominio.com/ssl.pem"
 ssl.ca-file = "/etc/lighttpd/ssl/midominio.com/ca.cer"
 ssl.dh-file = "/etc/lighttpd/ssl/midominio.com/dhparams.pem"

# ECDH/ECDHE ciphers curve strength 
 ssl.ec-curve = "secp384r1"

ssl.use-compression = "disable"

# Environment flag for HTTPS enabled
 setenv.add-environment = (
 "HTTPS" => "on"
 )
 ssl.use-sslv2 = "disable"
 ssl.use-sslv3 = "disable"
 ssl.honor-cipher-order = "enable"
 ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
 # HSTS(15768000 seconds = 6 months)
 setenv.add-response-header = (
 "Strict-Transport-Security" => "max-age=15768000;"
 )
}

Instalar el certificado

Creamos un script de instalación:

vi /root/.acme.sh/miburro.no-ip.org/hook.sh

Con el siguiente contenido. Como siempre ajustando midominio.com:

#!/bin/bash
dom="midominio.com"                    #your domain name 
dest="/etc/lighttpd/ssl/midominio.com" #lighttpd ssl path root
croot="/root/.acme.sh/${dom}"          #acme.sh root path for your domain
 
### NO edit below ###
sslfile="${dest}/ssl.pem"      #lighttpd .pem file path
certfile="${croot}/${dom}.cer" #lighttpd certficate file path 
keyfile="${croot}/${dom}.key"  #lighttpd key file path 
 
echo "Running lighttpd cmd..."
/bin/cat "${certfile}" "${keyfile}" > "${sslfile}"
/bin/systemctl restart lighttpd

Le damos permisos de ejecución:

chmod +x /root/.acme.sh/midominio.com/hook.sh

E instalamos:

acme.sh --installcert -d midominio.com --capath /etc/lighttpd/ssl/midominio.com/ca.cer --reloadcmd '/root/.acme.sh/midominio.com/hook.sh'

Y ya está. Si todo ha ido bien ahora todo el tráfico de nuestro servidor web se redirige a HTTPS con un certificado válido.

Por último, comentar que ahora en nuestro cron debe aparecer una línea similar a esta:

# Renovar certificado:
52 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

Esto lo que hace es cada noche comprobar si el certificado ha caducado y, si es caso, lo renueva.

Bibliografía

nixCraft

Lighttpd.net

MLDonkey 3.1.6 en Raspbian

Hace poco se liberó la última versión de MLDonkey. Aquí el anuncio. ¡La anterior era de 2014! Desde aquí todo mi agradecimiento a los responsables.

Vamos a ver cómo compilarlo en nuestra Rasbian Jessie.

Descargamos el código fuente:

wget https://github.com/ygrek/mldonkey/releases/download/release-3-1-6/mldonkey-3.1.6.tar.bz2

Descomprimimos:

tar xvfj mldonkey-3.1.6.tar.bz2

Accedemos al directorio del MLDonkey y ejecutamos el siguiente comando:

cd mldonkey-3.1.6/

./configure

En un momento dado nos pregunta si queremos descargar e instalar Ocalm. Le respondemos con una «y» para indicarle que sí y continuamos:

Do you want this script to try to download and install ocaml
LOCALLY in mldonkey directory ?
y

Esto llevará un rato así que puedes irte a por un café.

Si todo ha ido bien, el proceso terminará con los siguientes comentarios:

\nNow execute 'make' to start compiling. Good luck!

To compile a static code execute:     make mlnet.static
To produce a release tarball execute: make release.mlnet.static
To clean the build directory execute: make maintainerclean

Compiling CryptoPP.cc can take several minutes, on slow machines up to half an hour.

Es el momento de empezar a compilar:

make -j4

Nota sobre el «-j4»: en mi caso, como tengo una Raspberry Pi 2, he utilizado este parámetro para aprovechar las 4 CPU. Para la Pi 1 mejor ejecutar «make» a secas.

Este proceso en mi Pi2 no lleva más de 2 o 3 minutos y deja en el mismo directorio que nos encontramos el ejecutable mlnet.

No tenemos el típico «make install» así que tendremos que hacerlo a mano.

Paramos el MLDonkey:

sudo systemctl stop mldonkey-server

Hacemos una copia del actual mlnet (nunca se sabe):

sudo cp /usr/bin/mlnet /usr/bin/mlnet.old

Copiamos el nuevo mlnet:

sudo cp mlnet /usr/bin/mlnet

En estos momentos ya tenemos la nueva versión disponible en nuestro sistema. Podemos comprobarlo ejecutando:

 $ mlnet -v
2017/02/10 11:07:59 [cO] Starting MLDonkey 3.1.6 ...

Ya solo nos queda iniciar de nuevo el MLDonkey:

sudo systemctl start mldonkey-server

Nginx como proxy inverso

Hace tiempo contaba cómo configurar Lighttpd como proxy inverso. En esta ocasión haremos lo mismo pero con Nginx.

Nuestra intención es poder acceder a dos instancias de Calibre Server y que para ello el Nginx nos solicite usuario y contraseña.

Como siempre, lo primero es instalar el Nginx:

sudo apt install nginx-light

Nota: habréis visto que en los repositorios de Raspbian existen varios sabores de Nginx. Para nuestro propósito con la versión light es suficiente.

Una vez instalado detenemos el servidor:

sudo systemctl stop nginx

Y editamos el fichero de configuración del Nginx:

sudo vi /etc/nginx/sites-available/default

El fichero de configuración del Nginx tiene muchas opciones y es muy flexible. Yo solo comentaré lo necesario para nuestro proxy inverso:

location /libros1/ {
       proxy_pass http://127.0.0.1:8081;
       auth_basic "Restricted Content";
       auth_basic_user_file /etc/nginx/passwords;
}

location /libros2/ {
       proxy_pass http://127.0.0.1:8082;
       auth_basic "Restricted Content";
       auth_basic_user_file /etc/nginx/passwords;
}

Explico un poco los parámetros tomando como ejemplo el «libros1«:

  • location: este será el contexto de la URL donde será accesible el contenido. La URL final quedaría más o menos así: http://miraspberrypi/libros1
  • proxy_pass: es la IP y el puerto donde se encuentra el contenido. http://127.0.0.1:8081 en el ejemplo
  • auth_basic y auth_basic_user_file indican al Nginx que ha de pedir credenciales y que en el fichero /etc/nginx/passwords encontrará las credenciales válidas.

Y eso es todo, ya solo nos queda iniciar el Nginx:

sudo systemctl start nginx

¡Y a disfrutar!

PD: Para crear el fichero de passwords hemos de instalar el siguiente paquete:

sudo apt install apache2-utils

Y seguir las mismas instrucciones que comentaba en el post de Lighttpd.