Bibliobox (biblioteca digital autónoma)
Fugas tecno-lógicas
Bibliobox.isla
última actualización 2026.08.20
Conocimientos previos
No es necesario ser especialista en Linux, Docker o desarrollo web. Es recomendable tener cierta familiaridad con:
- Uso básico de una terminal
- Navegación por directorios (
cd, ls, cp.) - Copiar y mover archivos
- Uso básico de Git
- Conceptos básicos de redes
- Qué es una dirección IP
- Qué es una red Wi-Fi
Requisitos técnicos:
Computadora
- Linux instalado (Fedora, Debian, Ubuntu, Linux Mint, Arch, etc.)
- 4 GB de RAM como mínimo
- 10 GB de espacio libre en disco
- Al menos un puerto USB disponible
- Conexión a Internet
- Conexión Wi-Fi
- lector de tarjetas SD (integrado o por usb)
#1 Crear nuestra Rasberry Pi OS en la microSD:
-
Conlsblk -fencontramos el nombre de la memoria microSD comunmente llamada:of=/dev/mmcblk0` -
Luego
ddpodemos volcar la imagen en la memoria microSD del sistema operativo Rasperry Pi OS:
xzcat 2026-04-21-raspilsos-trixie-arm64-lite.img.xz | sudo dd of=/dev/mmcblk0 bs=4M status=progress conv=fsync
- Montar la partición boot > hacer antes del primer inicio (IMPORTANTE)
- primero vemos que particiones tenemos y con qué nombres
lsblk -f
- luego montamos boot y generamos usuarie y contraseña ej: bibliobox:bibliobox
echo "bibliobox:$(openssl passwd -6 bibliobox)" > userconf
- chequeamos que este creado
cat userconf
touch ssh
-
Conectamos la alimentación y el cable de red a la raspi junto con un router.
-
Buscar la raspi en el router o escanear la red
1
2
3
4
5
6
7
8
9
10
11
12
sudo arp-scan 192.168.1.0/24 (ip del portal del router)
Interface: wlp3s0, type: EN10MB, MAC: 7e:6f:05:a7:ed:80, IPv4: 192.168.1.49
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.1.1 2c:96:82:2b:58:44 (Unknown)
192.168.1.34 ec:2e:98:da:ee:b3 AzureWave Technology Inc.
192.168.1.48 a8:64:f1:f8:e2:1a Intel Corporate
192.168.1.50 ba:99:77:e5:86:0e (Unknown: locally administered)
192.168.1.51 e0:99:71:af:0e:4d Samsung Electronics Co.,Ltd
192.168.1.41 36:0e:52:19:9a:7a (Unknown: locally administered)
192.168.1.37 94:db:c9:f7:2b:ae AzureWave Technology Inc.
192.168.1.64 40:e2:30:f7:bd:15 AzureWave Technology Inc.
- Detectar en nuestro router que ip nos asigno para la rpi y entrar con ssh
por ej: ssh bibliobox@192.168.1.103
#2 Instalar bibliobox-script
La Raspberry Pi crea una red WiFi local y publica una biblioteca digital mediante un sitio web estático. También es accesible a través de un router si se lo conecta por eth0 con el nombre del http://$SSID.local.
Instalar dependencias para usar el repositorio bibliobox script
sudo apt update
sudo apt install git
- clonar el repositorio dentro de la RPi en el
~/home
git clone https://gitlab.com/librenauta/bibliobox-script.git
Configuración
Editar únicamente config.sh.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Bibliobox
SSID="Bibliobox"
DOMAIN="bibliobox.isla"
SITE_PATH="/srv/bibliobox.isla"
# Red
INTERFACE="wlan0"
IP="192.168.4.1"
SUBNET="24"
# DHCP
DHCP_RANGE_START="192.168.4.10"
DHCP_RANGE_END="192.168.4.100"
# WiFi | AR=argentina | México=MX
WIFI_COUNTRY="AR"
WIFI_CHANNEL="6"
# Portal
MAX_CLIENTS="100"
SSID es el nombre de la red de Wifi y también el nombre del dominio .local
DOMAIN y SITE_PATH son independientes pero están relacionados:
DOMAINes el nombre que puede escribir una persona en el navegador.SITE_PATHes el directorio donde Nginx busca la biblioteca.
Por ejemplo:
1
2
3
4
5
http://bibliobox.isla
↓
192.168.4.1
↓
/srv/bibliobox.isla
Instalación completa
Desde este directorio:
1
2
# usamos sudo bash asi no tenemos que asignarle permisos de ejecución a cada script
sudo bash install.sh
Instalación por etapas
Cada etapa puede ejecutarse por separado:
1
2
3
4
5
6
sudo bash ./01-paquetes.sh
sudo bash ./02-red.sh
sudo bash ./03-wifi.sh
sudo bash ./04-portal.sh
sudo bash ./05-sitio.sh
sudo bash ./06-avahi.sh
Cada script carga automáticamente la configuración desde config.sh.
1
2
3
4
5
6
7
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ CELULAR │ │ hostapd │ │ dnsmasq │ │ nginx │
│ │───▶│ Bibliobox │───▶│ │───▶│ │
│ conecta a │ WiFi│ │ │ bibliobox.isla │ │ root │
│ WiFi │ │ │ │ ↓ │ │ /srv/bibliobox.isla│
└──────────────┘ └──────────────────┘ │ 192.168.4.1 │ └────────────────────┘
└──────────────────┘
- Paso a paso de las etapas del script
install.sh
Este script llama a cada etapa en forma de cascada y toma como fuente de variables globales lo que definimos en config.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
echo "[install] Iniciando instalación de Bibliobox"
echo "[install] WiFi: $SSID"
echo "[install] Dominio: $DOMAIN"
echo "[install] Sitio: $SITE_PATH"
echo "[install] URL para acceder si conectamos un router a la RPI http://$MDNS_HOSTNAME.local"
bash "$SCRIPT_DIR/01-paquetes.sh"
bash "$SCRIPT_DIR/02-red.sh"
bash "$SCRIPT_DIR/03-wifi.sh"
bash "$SCRIPT_DIR/04-portal.sh"
bash "$SCRIPT_DIR/05-sitio.sh"
bash "$SCRIPT_DIR/06-avahi.sh"
echo "[install] Habilitando servicios"
systemctl unmask hostapd
systemctl enable \
hostapd \
dnsmasq \
nginx \
nodogsplash
echo "[install] Reiniciando servicios"
systemctl restart dhcpcd || true
systemctl restart dnsmasq
systemctl restart hostapd
systemctl restart nginx
systemctl restart nodogsplash
echo "[install] Instalación completa ∩`-´)⊃━☆゚.*・。゚*.-"
echo "[install] WiFi: $SSID"
echo "[install] Portal: http://$DOMAIN/"
echo "[install] IP: http://$IP/"
echo "[install] Ubicación del sitio: $SITE_PATH"
echo "[install] URL .local: http://$MDNS_HOSTNAME.local"
01-paquetes.sh
Instalamos los paquetes necesarios para nuestra instalación.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
log() {
echo "[Ejecutando 01-paquetes] $1"
}
log "Instalando paquetes"
apt update
apt install -y \
hostapd \
dnsmasq \
nginx \
rfkill \
git \
build-essential \
libmicrohttpd-dev \
libjson-c-dev \
dhcpcd5
02-red.sh
configuramos una ip estática y configuramos dnsmasq que permite generar un dns local así podemos usar nuestro dominio personalizado (sin https).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
log() {
echo "[Ejecutando 02-red] $1"
}
log "Deteniendo servicios"
systemctl stop hostapd dnsmasq nginx nodogsplash 2>/dev/null || true
log "Desactivando wpa_supplicant"
systemctl disable wpa_supplicant 2>/dev/null || true
systemctl stop wpa_supplicant 2>/dev/null || true
log "Configurando IP estática"
if ! grep -q "$IP" /etc/dhcpcd.conf 2>/dev/null; then
cat <<EOF >> /etc/dhcpcd.conf
interface $INTERFACE
static ip_address=$IP/$SUBNET
nohook wpa_supplicant
EOF
fi
log "Activando IP forwarding"
if ! grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf; then
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
fi
log "Configurando dnsmasq"
if [ ! -f /etc/dnsmasq.conf.bak ]; then
mv /etc/dnsmasq.conf /etc/dnsmasq.conf.bak 2>/dev/null || true
cat <<EOF > /etc/dnsmasq.conf
interface=$INTERFACE
dhcp-range=$DHCP_RANGE_START,$DHCP_RANGE_END,255.255.255.0,12h
address=/#/$IP
EOF
fi
03-wifi.sh
Configuramos hostapd para generar el hotspot (Generar red de Wifi), creamos el servicio en systemd para que inice al reiniciar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
log() {
echo "[Ejecutando 03-wifi] $1"
}
log "Desbloqueando WiFi"
if rfkill list wifi | grep -q "Soft blocked: yes"; then
rfkill unblock wifi
fi
log "Configurando país WiFi: $WIFI_COUNTRY"
iw reg set "$WIFI_COUNTRY" || true
log "Configurando hostapd"
cat <<EOF > /etc/hostapd/hostapd.conf
interface=$INTERFACE
driver=nl80211
ssid=$SSID
hw_mode=g
channel=$WIFI_CHANNEL
auth_algs=1
ignore_broadcast_ssid=0
EOF
sed -i \
's|^#DAEMON_CONF=.*|DAEMON_CONF="/etc/hostapd/hostapd.conf"|' \
/etc/default/hostapd 2>/dev/null || \
echo 'DAEMON_CONF="/etc/hostapd/hostapd.conf"' >> /etc/default/hostapd
log "Creando servicio wlan0-up"
cat <<EOF > /etc/systemd/system/wlan0-up.service
[Unit]
Description=Levantar wlan0
Before=hostapd.service
[Service]
Type=oneshot
ExecStart=/sbin/ip link set $INTERFACE up
[Install]
WantedBy=multi-user.target
EOF
systemctl enable wlan0-up
log "Creando servicio rfkill-unblock"
cat <<EOF > /etc/systemd/system/rfkill-unblock.service
[Unit]
Description=Unblock WiFi
Before=hostapd.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c "sleep 2 && rfkill unblock wifi"
[Install]
WantedBy=multi-user.target
EOF
systemctl enable rfkill-unblock
04-portal.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
log() {
echo "[Ejecutando 04-portal] $1"
}
log "Configurando nginx"
rm -f /etc/nginx/sites-enabled/default
cat <<EOF > /etc/nginx/sites-available/bibliobox
server {
listen 80 default_server;
server_name $DOMAIN bibliobox.local _;
root $SITE_PATH;
index index.html;
location / {
try_files \$uri /index.html;
}
}
EOF
ln -sf /etc/nginx/sites-available/bibliobox \
/etc/nginx/sites-enabled/bibliobox
log "Instalando Nodogsplash"
if ! command -v nodogsplash >/dev/null; then
cd /tmp
rm -rf nodogsplash
git clone https://github.com/nodogsplash/nodogsplash.git
cd nodogsplash
make
make install
fi
log "Configurando servicio nodogsplash"
cat <<EOF > /etc/systemd/system/nodogsplash.service
[Unit]
Description=Nodogsplash Captive Portal
After=hostapd.service dnsmasq.service
Wants=hostapd.service dnsmasq.service
[Service]
ExecStart=/usr/local/bin/nodogsplash -f
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reexec
log "Configurando nodogsplash"
if [ ! -f /etc/nodogsplash/nodogsplash.conf ]; then
mkdir -p /etc/nodogsplash
cat <<EOF > /etc/nodogsplash/nodogsplash.conf
GatewayInterface $INTERFACE
GatewayAddress $IP
MaxClients $MAX_CLIENTS
SplashPage none
AuthenticateImmediately yes
RedirectURL http://$IP/
FirewallRuleSet authenticated-users {
FirewallRule allow all
}
FirewallRuleSet preauthenticated-users {
FirewallRule allow tcp port 80
FirewallRule allow tcp port 443
FirewallRule allow udp port 53
}
EOF
fi
05-sitio.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
log() {
echo "[Ejecutando 05-sitio web] $1"
}
log "Preparando sitio"
mkdir -p "$SITE_PATH"
if [ ! -f "$SITE_PATH/index.html" ]; then
cat <<EOF > "$SITE_PATH/index.html"
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$DOMAIN</title>
</head>
<body style="margin:0;background:#000;color:#fff;font-family:monospace;display:flex;align-items:center;justify-content:center;min-height:100vh;text-align:center;padding:2rem;box-sizing:border-box;">
<main>
<h1 style="margin:0 0 1rem;font-size:clamp(20px,4vw,26px);font-weight:400;line-height:1.4;">
Bibliobox creada en el CCD | CDMX
</h1>
<p style="margin:0;font-size:clamp(14px,2.5vw,16px);line-height:1.6;">
reemplaza este sitio por tu biblioteca
</p>
</main>
</body>
</html>
EOF
fi
06-avahi.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
log() { echo "[Ejecutando 06-avahi] $1"; }
log "SSID original: '$SSID' -> Nombre de host mDNS: '$MDNS_HOSTNAME'"
log "Instalando avahi-daemon y herramientas"
apt install -y avahi-daemon avahi-utils
log "Configurando nombre de host a '$MDNS_HOSTNAME'"
CURRENT_HOSTNAME=$(hostname)
if [ "$CURRENT_HOSTNAME" != "$MDNS_HOSTNAME" ]; then
hostnamectl set-hostname "$MDNS_HOSTNAME"
# Actualizar /etc/hosts para que el sistema se reconozca a sí mismo
sed -i "s/^127.0.1.1\s*.*/127.0.1.1\t$MDNS_HOSTNAME/" /etc/hosts
fi
log "Habilitando e iniciando avahi-daemon"
systemctl enable avahi-daemon
systemctl restart avahi-daemon
log "Avahi andando. La RPi se anunciará como $MDNS_HOSTNAME.local en todas las interfaces."
Con esto ejecutado tenemos nuestra Raspberry PI que inicia y genera una red de wifi sirviendo un sitio según el nombre que asignamos en config.sh
Equipo donde gestionamos la biblioteca.
- Instalar [Calibre] este será el lugar donde volcaremos los libros y los organizarémos por etiquetas, autoras, series.
- Volcar libros en una biblioteca.
- Editar metadata de los libros y asegurarnos que tienen todos portadas [tapas], en el buscador de calibre podemos poner:
cover:falsepara filtrar los libros que no tengan una tapa, y podemos crearle una enModificar metadatos > Generar portada
git clone https://gitlab.com/librenauta/bibliobox-docker.git
sudo docker pull registry.gitlab.com/librenauta/bibliobox-docker:latest
sudo docker compose run --rm bibliobox
- clonar el repositorio bibliobox-docker con:
git clone https://gitlab.com/librenauta/bibliobox-docker.git
cd bibliobox-docker/bibliobox-jekyll-theme
- Dentro de bibliobox-docker/bibliobox-jekyll-theme/books copiar con rsync nuestra biblioteca.
la carpeta donde guardamos nuestra biblioteca tiene que tener:
- directorios con nombre de lxs autorxs
- un archivo llamado
metadata.db
- Con un programa que se llama
rsyncvamos a copiar nuestra carpeta./booksal directorio correspondiente en la Raspberry PI
rsync -avHAX --progress books/ bibliobox@bibliobox.isla:/usr/bibliobox/bibliobox-docker/bibliobox-jekyll-theme/books
- Dentro de
bibliobox-jekyll-themeutilizar la imagen de docker con jekyll para compilar el sitio:
sudo docker compose pull
- Para compilar el sitio (crear la biblioteca sitio en base a los libros de la biblioteca de calibre)
sudo docker compose run --rm bibliobox
- Tenemos el sitio generado localmente en la RPi en
bibliobox-jekyll-theme/_site
lo copiamos a nuestro directorio del servidor web para hacerlo disponible en la Red: sudo cp -r _site/. /srv/bibliobox.isla/
Ya tenemos disponible nuestra biblioteca-sitioweb con el dominio que asignamos en config.sh
A compartir!
