← HDA-NAS | ↑ HDA-SERV | HDA-DOCKER →
Buenas de nuevo, queridos mediavidensis,
Allá en febrero del 22 monté un tuto sobre la adquisición de un NAS para backup en casa. En aquel hilo caminé pormenorizadamente por el concepto de NAS, la selección del mismo, el hardware, y los discos duros. Terminaba aquel hilo indicando que sería el primero en una serie de tres: 1) Hardware, 2) Configuración del sistema, y 3) Microservicios. Pues bien, este que tenéis delante es el segundo hilo de la saga, el de la configuración del sistema.
La razón de la existencia de este hilo es que conforme iba instalando todo, también iba documentándolo. Así que mi propósito es adaptar un poco las notas que he ido tomando para compartirlas con vosotros. Seguro que muchos podrán aportar y recomendar diferentes cosas, ¡y agradecido de antemano quedo! He intentado mantener hipervínculos a las fuentes que he ido recorriendo, de tal guisa que no entro en la explicación de cada uno de los pasos a bajo nivel. Si queréis saber más sobre algo específico podéis acceder al hipervínculo asociado. Por último, esta instalación está hecha para mi caso de uso, mis necesidades y mi entorno. Lo bueno de los sistemas *nix es que son harto configurables, por lo que cada uno puede encontrar la solución que más se le ajuste y le guste.
Antes de continuar, tal como hice en el anterior hilo, debo comentar que no soy ningún experto a bajo nivel en la materia. Tengo nociones de linux porque hace tiempo que juego con él (de ahí mi nick), pero no soy profesional de sistemas o redes ni de coña. Mi trasfondo es de programador y de físico, pero siempre he sido entusiasta de la informática y desde pequeño me he dedicado a montar, desmontar y formatear mis ordenadores. Sin embargo, la parte del entendimiento tecnológico fundamental le corresponde a un ingeniero informático reglado, para mí todo esto es solo entretenimiento.
Varios de los pasos que comentaré en este y los otros hilos de la serie requieren de conocimientos de hardware, de administración de sistemas, de securización y de backend. Soy un novato en el asunto pero me gusta aprehender. Lo que quiero decir con esto es que lo que comparto puede estar errado. Por favor, si encontráis algún error de contenido o forma, hacédmelo saber. Este hilo es solo una guía de instalación y configuración de un ordenador con el objetivo de ser un homelab/servidor casero.
Algunas partes de la configuración son extensas. Además, como esta configuración es integral, no me voy a detener en qué es cada una de las cosas que instalo/configuro. Si tenéis alguna duda respecto a algún paquete, servicio, configuración o plugin, simplemente preguntad en este hilo o buscar en la red para qué sirve.
- Índice
- Preámbulo
- Primeros pasos
- Macroconfiguración de zsh
- Instalando CUDA drivers
- Instalando zfs
- Samba
- Docker
- Servidor DNS Pi-Hole
- Palabras finales
2. - Preámbulo ↑
2.1. - Motivación ↑
Tras casi dos años usando el NAS de synology (hda-nas) se me ha quedado muy, muy corto). La razón es que empecé a exigirle bastante. Más allá de salirme de la caja de DSM (el OS privativo de synology) para configurar a mi gusto muchas cosas de *nix, resulta que le estaba exigiendo demasiado al pobre ordenador. En los últimos años me he convertido en un gran aficionado de docker, y el ds920+ simplemente no podía con los microservicios que yo le estaba exigiendo o quería exigirle.
Recientemente, he adquirido un nuevo ordenador para el trabajo, así que mi ordenador antiguo ha quedado libre de pecado. Por tanto, era un perfecto momento de reaprovecharlo un poco, transformándolo en mi homelab, y así trastear, montar microservicios y demás tonterías. Es decir, el segundo de esta trilogía de hilos no va sobre la configuración de un sistema DSM sino sobre la instalación y puesta a punto de un homelab casero. Usaré la última versión de Debian, Debian 12, sin interfaz gráfica (sin X11). En el tercer hilo hablaré sobre los microservicios que lanzo, dando justificación al hardware.
2.2. - ¿Qué es un homelab?, ¿por qué un homelab? ↑
Lo primero que debemos preguntarnos es ¿qué es un homelab y por qué debería interesarnos? Un homelab representa un espacio de laboratorio informático montado en casa, diseñado para experimentar con nuevas tecnologías y adquirir conocimientos sobre redes y gestión de sistemas. Algunas razones para montar de un homelab podrían ser:
-
Exploración de nuevas tecnologías: El homelab ofrece una vía excelente para adentrarse y poner a prueba distintas tecnologías en un entorno seguro. Esto implica la instalación de diversos sistemas operativos, experimentación con diversos servicios y el aprendizaje en la configuración y administración de distintos tipos de hardware.
-
Desarrollo de habilidades en gestión de sistemas: En un homelab puedes fortalecer y expandir tus habilidades en la gestión de sistemas. Aquí se pueden adquirir conocimientos en la configuración y administración de servidores, redes, almacenamiento y otros sistemas informáticos.
-
Economía: Mediante un homelab puedes, aprovechando el hardware que ya tengas por casa, montarte tu juguete que puede servir como alternativa para reducir costes asociados a servicios en la nube. Como instalamos y gestionamos nuestros propios servidores y servicios podemos acceder a ellos sin depender de plataformas externas.
2.3. - Hardware ↑
Lo que haré será reaprovechar mi ordenador antiguo intentando gastar poco en su puesta a punto. Empecé haciendo una limpieza integral de la caja. Cambié dos de los ventiladores antiguos que tras casi siete años ya traqueteaban un poco. También cambié la pasta térmica del procesador. De pura suerte, tras hacer esto, la AIO del CPU murió, así que compré un disipador bien valorado actualmente (Thermalright Assasin 120E) y sustituí la AIO estropeada. También adquirí dos discos duros EXOS x18 Enterprise de 18 Tb. Lo último que compré fue una tarjeta de red de 10 Gb TP-Link TX401.
A continuación listaré pero no entraré en las especificaciones técnicas del hardware final, como sí hiciera en el hilo anterior.
- OS: Debian 12
- CPU: Intel i7 7700 k
- GPU: Gigabyte AORUS GeForce RTX 3080 MASTER (Rev.1.0) 10GB GDDR6
- MOBO: Asus ROG STRIX Z270E GAMING
- PSU: Corsair RMX750 80 Plus Gold 750W
- RAM: 4 × 8 Gb (32 Gb) KFA2 HOF Hall Of Fame 3600MHz (PC4-28800) CL17
- HDD M.2: 2 × 1000 Gb (2 Tb) Samsung SSD 970 EVO Plus + Crucial CT1000P1SSD8
- HDD SATA: 2 × 18 Tb (36 Tb) EXOS x18 Enterprise
- NIC: 1 × TP-Link TX401) (10 Gb RJ45
Quitando los ventiladores y el disipador, por manteminiento, esto es lo único que he comprado para metamorfosear mi antigua battlestation en un servidor.
Recientemente, he actualizado mi LAN y mi WAN a 10 Gb, razón por la que le he metido este NIC al servidor. Mi PC de trabajo va con un NIC 10G integrado, y al NAS le puse un NIC de 5 Gb por usb 3.0 (QNAP QNA-UC5G1T). Estos dispositivos van a un HUB tonto de 10G (TL-X105), que conecta al único puerto 10G que monta el router (ZTE F8648P) de mi ISP (DIGI). Como varios de los servicios que pretendo consumen ancho de banda, para mí era relevante actualizar la LAN y la WAN. Mi intención es que el servidor gestione todas las conexiones de mis dispositivos a través de openVPN. Es decir, toda navegación, desde los vídeos en los móviles hasta las películas en netflix 4k, sin olvidar los [backups](https://www.synology.com/en-global/dsm/feature/active-backup-business/pc diarios hacia el NAS), pasarán por el servidor, pudiendo haber concurrencia. También es importante para temas de torrent/seedbox, así como para Plexy algún servidor de juegos que pretendo.
3. - Primeros pasos ↑
Esta guía parte de una instalación fresca de Debian 12. Para ello, se ha montado un pendrive y se ha hecho una instalación regular sin marcar el entorno gráfico en la instalación. Este ha sido el único momento en el que conectaremos un teclado y una pantalla al ordenador. A partir de aquí, todo el servidor será manejado en entorno consola mediante una conexión SSH (configurada durante la instalación).
Así que nos conectamos al servidor mediante ssh y... ¡empezamos!:
3.1. - Sources list ↑
Como hemos instalado Debian 12 desde usb debemos comentar la línea en sources list pues, si no, tendremos error con el apt dado que intentará acceder al usb cada vez. Así que, como root:
nano /etc/apt/sources.list
Comentamos las líneas referentes al cdrom (la "#" antes de la línea)
#deb cdrom:[Debian GNU/Linux 12.2.0 _Bookworm_ - Official amd64 DVD Binary-1 with firmware 20231007-10:29]/ bookworm main non-free-firmware
3.2. - Sudo ↑
Para mayor comodidad instalaremos "sudo", de modo que podamos ejecutar comandos de root desde nuestro usuario, previa identificación. Actualizamos apt-get e instalamos sudo
sudo apt update -y && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo apt clean -y && sudo apt autoclean -y
apt-get install sudo
Con esto lo tenemos instalado, solo falta que añadamos nuestro usuario a sudoers (mi usuario es "hda", cámbialo por el tuyo):
usermod -aG sudo hda
3.3. - SSH Config ↑
Procedemos configurando el ssh para loguear con ssh key y no con contraseña. Esto hace la autentificación más segura y sencilla.
- Creamos (si no tenemos ya) la clave en el ordenador local: ssh-keygen
- Copiamos nuestra clave pública en el servidor
ssh-copy-id hda@HDA-SERV
# primero creamos al carpeta .ssh/ en nuestra home del servidor
mkdir ~/hda/.ssh
# luego en consola de windows desde la carpeta ssh donde creamos previamente las claves, la copiamos al servidor:
scp id_ed25519.pub hda@HDA-SERV:/home/hda/.ssh/authorized_keys
Aplicamos los permisos correctos a nuestra carpeta .ssh
chmod 700 /home/hda/.ssh && chmod 600 /home/hda/.ssh/authorized_keys
chown -R hda:hda /home/hda/.ssh
Ahora configuraremos el servidor SSH a nuestro gusto, partiendo del siguiente archivo podemos cambiar varias cosas:
sudo nano /etc/ssh/sshd_config
Podemos cambiar las siguientes cosas:
Port 4444 #Cambio de puerto SSH
PasswordAuthentication no #Deshabilitar el login por contraseña
PermitRootLogin no #Deshabilitar el Root login
Por último reiniciamos el servicio:
sudo systemctl restart ssh
Y con esto tenemos el ssh configurado por completo.
3.4. - Firewall↑
El siguiente paso será instalar un firewall en el sistema. Usaremos Uncomplicated Firewall. Y lo configuraremos de tal modo que por defecto prohiba toda conexión entrante, pero permita la saliente. Además, añadiremos la regla para que acepte conexiones ssh (del paso anterior). Todo esto es fácil con los siguientes pasos:
sudo apt-get -y install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 4444 #Add rules on ssh port
sudo ufw enable
sudo reboot
3.5. - Wake on Lan ↑
¡Es importante que el servidor se pueda levantar mediante Wake on Lan! Si por alguna razón se encuentra en estado apagado (Estado S5), necesitamos poder encenderlo remotamente. Para ello, la tarjeta de red debe ser compatible (la g en la siguiente imagen):
sudo apt-get -y install ethtool
ip link show # listamos los interfaces
sudo ethtool enp3s0 #chequeamos el interfaz objetivo
Imagen 1. Captura de pantalla con la información WOL del NIC. En el caso de que lo sea, lo activamos con:
sudo ethtool -s enp3s0 wol g
sudo reboot
3.6. - Restos de la configuración básica↑
Aprovechando este enlace y el feedback del compañero @carracho vamos a configurar un par de cosas más
El propósito de UnattendedUpgrades es mantener la máquina con los últimos updates de seguridad, así que se lo metemos al servidor y lo configuramos.
sudo apt-get -y install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
Podemos listar los timezones mediante:
timedatectl list-timezones
y a continuación establecemos el que deseemos:
sudo timedatectl set-timezone Europe/Madrid
Ahora instalamos ntp, Network Time Protocol, sirve para sincronizar el reloj del ordenador con servidores de sincronización. Hacer esto es una buena práctrica para mantener los logs del servidor ajustados.
apt-get -y install ntp
sudo /etc/init.d/ntpsec start
Con esto ya tenemos configurado el tiempo del ordenador.
Ponerle nombre a la máquina. Podemos ponerle un FQDN o un identificador, lo que más nos convenga
sudo hostnamectl set-hostname HDA-SERV
Podemos editar hosts para añadir este nombre:
sudo nano /etc/hosts
Y añadimos la línea
127.0.0.1 localhost HDA-SERV
Este paso de hosts, relacionando la IP del servidor con un nombre, habría que repetirlo en los ordenadores de la lan para que el servidor sea reconocible por nombre (y no necesariamente por IP). Otra opción es configurarlo en el router si vas con DHCP. Existen varias alternativas para conseguir esto.
El GRUB es programa que carga el kernel del OS elegido. Una cosilla sencilla que podemos hacer para que el boot sea más rápido es cambiar el timeout del GRUB a uno más corto. Editamos ese tiempo en el siguiente archivo:
sudo nano /etc/default/grub
y después lo actualizamos:
sudo update-grub
Entre los varios paquetes que hemos instalado previamente, uno de ellos fue neofetch. Este es un programa que nos da la info del sistema. En esta configuración esta info la dará automáticamente al loguear por ssh. Para adaptar neofetch al gusto editamos el archivo:
nano ~/.config/neofetch/config.conf
y, para mi gusto, añadimos:
print_info() {
info title
info underline
info "OS" distro
info "Host" model
info "Kernel" kernel
info "Uptime" uptime
info "Packages" packages
info "Shell" shell
info "Resolution" resolution
info "DE" de
info "WM" wm
info "WM Theme" wm_theme
info "Theme" theme
info "Icons" icons
info "Terminal" term
info "Terminal Font" term_font
info "CPU" cpu
info "CPU Usage" cpu_usage
info "GPU" gpu
info "GPU Driver" gpu_driver # Linux/macOS only
info "Memory" memory
info "Disk" disk
# info "Battery" battery
# info "Font" font
# info "Song" song
# [[ "$player" ]] && prin "Music Player" "$player"
# info "Local IP" local_ip
# info "Public IP" public_ip
# info "Users" users
# info "Locale" locale # This only works on glibc systems.
info cols
}
También cambiamos la siguiente línea de modo que de la temperatura en centígrados:
cpu_temp="C"
Mediante logrotate tendremos mejores logs para las aplicaciones que gustemos. Dejamos en avance configurado logrotate para traefik, contenedor que veremos en el siguiente hilo de la serie. Para ello creamos el siguiente archivo:
sudo nano /etc/logrotate.d/traefik
y lo llenamos con
/opt/traefik/logs/*.log {
daily
rotate 30
missingok
notifempty
compress
dateext
dateformat .%Y-%m-%d
create 0644 root root
postrotate
docker kill --signal="USR1" $(docker ps | grep '\btraefik\b' | awk '{print $1}')
endscript
}
Nota: el contenedor ha de llamarse traefik y deberá tener montado este volumen:
volumes:
- /opt/traefik/logs:/logs
4. - Macroconfiguración de zsh ↑
4.1. - Instalando el core ↑
Ahora instalaremos una shell hipervitaminada a nuestro usuario. En concreto zsh+ohmyzsh+powerlevel. Lo haremos bastante del tirón. Hemos de tener en cuenta que la siguiente configuración es la que a mí me gusta, para otros podría ser diferente.
sudo apt-get -y install zsh git fonts-powerline eza fzf neofetch bat
sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Reiniciamos la consola, debería cargarnos directamente zsh. Ahí podremos instalar powerlevel 10k:
git clone https://github.com/romkatv/powerlevel10k.git $ZSH_CUSTOM/themes/powerlevel10k
En el .zshrc cambiamos el ZSH_THEME a p10k:
#ZSH_THEME="robbyrussell" #comentamos el theme anterior
ZSH_THEME="powerlevel10k/powerlevel10k" #e indicamos el p10k theme
Reiniciamos la consola y procedemos con la configuración de powerlevel.
4.2. - oh-my-zsh plugins ↑
Reentramos en la consola y debería cargarnos directamente zsh. Lo siguiente será descargar los plugins de oh-my-zsh que nos interesen. La siguiente es una colección con los instaladores de plugins que yo uso. Plugins oh-my-zsh:
#fast-syntax-highlighting
git clone https://github.com/zdharma-continuum/fast-syntax-highlighting.git \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/fast-syntax-highlighting
#fzf-zsh-plugin
git clone --depth 1 https://github.com/unixorn/fzf-zsh-plugin.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/fzf-zsh-plugin
#zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
#zsh-completions
git clone https://github.com/zsh-users/zsh-completions ${ZSH_CUSTOM:-${ZSH:-~/.oh-my-zsh}/custom}/plugins/zsh-completions
fpath+=${ZSH_CUSTOM:-${ZSH:-~/.oh-my-zsh}/custom}/plugins/zsh-completions/src
#zsh-fzf-history-search
git clone https://github.com/joshskidmore/zsh-fzf-history-search ${ZSH_CUSTOM:=~/.oh-my-zsh/custom}/plugins/zsh-fzf-history-search
#zsh-history-substring-search
git clone https://github.com/zsh-users/zsh-history-substring-search ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-history-substring-search
#zsh-shift-select
git clone https://github.com/jirutka/zsh-shift-select.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-shift-select
#zsh-you-should-use
git clone https://github.com/MichaelAquilina/zsh-you-should-use.git $ZSH_CUSTOM/plugins/you-should-use
4.3. - Configurando .zshrc ↑
Lo siguiente que toca es poner al gusto la zsh, para ello editamos el archivo mediante:
nano .zshrc
Añadimos a la parte superior del archivo todo lo siguiente:
neofetch
# AUTOCOMPLETION
# initialize autocompletion
autoload -U compinit && compinit
# history setup
setopt SHARE_HISTORY
HISTFILE=$HOME/.zhistory
SAVEHIST=3000
HISTSIZE=2999
setopt HIST_EXPIRE_DUPS_FIRST
Podemos cambiar la forma en la que se nos presentan las fechas cambiando la siguiente línea:
HIST_STAMPS="dd/mm/yyyy"
En la parte de plugins activamos los que hayamos descargado, para ello ponemos:
plugins=(
fast-syntax-highlighting
git
alias-finder
zsh-autosuggestions
zsh-completions
zsh-fzf-history-search
zsh-history-substring-search
zsh-shift-select
you-should-use
)
Añadimos la siguiente línea encima de "source $ZSH/oh-my-zsh.sh"
fpath+=${ZSH_CUSTOM:-${ZSH:-~/.oh-my-zsh}/custom}/plugins/zsh-completions/src
Los alias son atajos de consola que simplifican mucho la vida. Yo uso unos cuantos, además de que he fusilado muchos para el futuro manejo de docker. Para añadir los alias, en el .zshrc, bajo "Example aliases" ponemos lo siguiente:
# Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"
#batcat to bat
alias bat='batcat'
# general use
alias ls='eza --icons' # ls
alias l='eza -lbF --icons --git' # list, size, type, git
alias ll='eza -lbGF --icons --git' # long list
alias llm='eza -lbGd --icons --git --sort=modified' # long list, modified date sort
alias la='eza -lbhHigUmuSa --icons --time-style=long-iso --git --color-scale' # all list
alias lx='eza -lbhHigUmuSa@ --icons --time-style=long-iso --git --color-scale' # all + extended list
# specialty views
alias lS='eza -1 --icons' # one column, just names
alias lt='eza --tree --icons --level=2' # tree
# set Safetynets
alias sudo='sudo ' # This allows sudo to run aliases
alias chmod='chmod --preserve-root'
alias chown='chown --preserve-root'
alias chgrp='chgrp --preserve-root'
# update stuff
alias aptup='sudo apt update -y && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo apt clean -y && sudo apt autoclean -y && pihole -up'
# navigation
alias prog='cd /SERV-PROG/'
alias data='cd /SERV-DATA/'
############################################################################
# #
# ------- Useful Docker Aliases -------- #
# #
# # Installation : #
# copy/paste these lines into your .bashrc or .zshrc file or just #
# type the following in your current shell to try it out: #
# wget -O - https://gist.githubusercontent.com/jgrodziski/9ed4a17709baad10dbcd4530b60dfcbb/raw/d84ef1741c59e7ab07fb055a70df1830584c6c18/docker-aliases.sh | bash
# #
# # Usage: #
# daws <svc> <cmd> <opts> : aws cli in docker with <svc> <cmd> <opts> #
# dbash <container>: run a bash shell into a given container #
# dc : docker compose #
# dcu : docker compose up -d #
# dcd : docker compose down #
# dcr : docker compose run #
# dex <container>: execute a bash shell inside the RUNNING <container> #
# dsh <container>: run a sh shell into a given container #
# di <container> : docker inspect <container> #
# dim : docker images #
# dip : IP addresses of all running containers #
# dl <container> : docker logs -f <container> #
# dnames : names of all running containers #
# dps : docker ps #
# dpsa : docker ps -a #
# drmc : remove all exited containers #
# drmid : remove all dangling images #
# drun <image> : execute a bash shell in NEW container from <image> #
# dsr <container>: stop then remove <container> #
# #
############################################################################
function dbash-fn {
docker exec -it $(docker ps -aqf "name=$1") bash;
}
function dsh-fn {
docker exec -it $(docker ps -aqf "name=$1") sh;
}
function dnames-fn {
for ID in `docker ps | awk '{print $1}' | grep -v 'CONTAINER'`
do
docker inspect $ID | grep Name | head -1 | awk '{print $2}' | sed 's/,//g' | sed 's%/%%g' | sed 's/"//g'
done
}
function dip-fn {
echo "IP addresses of all named running containers"
for DOC in `dnames-fn`
do
IP=`docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' "$DOC"`
OUT+=$DOC'\t'$IP'\n'
done
echo -e $OUT | column -t
unset OUT
}
function dex-fn {
docker exec -it $1 ${2:-bash}
}
function di-fn {
docker inspect $1
}
function dl-fn {
docker logs -f $1
}
function drun-fn {
docker run -it $1 $2
}
function dcr-fn {
docker compose run $@
}
function dsr-fn {
docker stop $1;docker rm $1
}
function drmc-fn {
docker rm $(docker ps --all -q -f status=exited)
}
function drmid-fn {
imgs=$(docker images -q -f dangling=true)
[ ! -z "$imgs" ] && docker rmi "$imgs" || echo "no dangling images."
}
# in order to do things like dex $(dlab label) sh
function dlab {
docker ps --filter="label=$1" --format="{{.ID}}"
}
function dc-fn {
docker compose $*
}
function d-aws-cli-fn {
docker run \
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
amazon/aws-cli:latest $1 $2 $3
}
alias daws=d-aws-cli-fn
alias dbash=dbash-fn
alias dc=dc-fn
alias dcu="docker compose up -d"
alias dcd="docker compose down"
alias dcr=dcr-fn
alias dex=dex-fn
alias dsh=dsh-fn
alias di=di-fn
alias dim="docker images"
alias dip=dip-fn
alias dl=dl-fn
alias dnames=dnames-fn
alias dps="docker ps"
alias dpsa="docker ps -a"
alias drmc=drmc-fn
alias drmid=drmid-fn
alias drun=drun-fn
alias dsp="docker system prune --all"
alias dsr=dsr-fn# docker bindkeys
# autocompletion using arrow keys (based on history)
bindkey '\e[A' history-search-backward
bindkey '\e[B' history-search-forward
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
#nvidia cuda stuff
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda/lib64
Con el alias aptup pondrás al día el apt, descuida por el error de pihole, que instalaremos más adelante. Además de los alias también incluye control para poder seleccionar y navegar con el teclado entre palabras más fácilmente, además de información sobre nvidia CUDA necesaria para el siguiente paso.
5. - Instalando CUDA drivers ↑
En mi caso, además de la gráfica integrada del procesador, me interesa que el sistema reconozca la GPU de nvidia con los drivers propietarios para hacer uso de CUDA. Para ello debemos instalar los drivers de la gráfica. Cabe destacar que, además de instalar los prerrequisitos y configurar los drivers, es necesario desactivar los drivers nvidia Nouveau, no propietarios, que integra debian por defecto.
sudo apt-get -y install gcc make chafa exiftool software-properties-common
Desactivar nouveau, creamos el siguiente archivo:
sudo nano /etc/modprobe.d/blacklist-nouveau.conf
Y lo llenamos con:
blacklist nouveau
options nouveau modeset=0
Después regeneramos el kernel initramfs y reiniciamos:
sudo update-initramfs -u
sudo apt-get install linux-headers-$(uname -r)
sudo add-apt-repository contrib
sudo apt-key del 7fa2af80
sudo reboot
Luego descargamos el cuda-keyring package, actualizamos apt, instalamos y reiniciamos:
wget https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install cuda
sudo reboot
6. - Instalando zfs ↑
Una de las cosas que me propuse con este servidor es jugar con el sistema de archivos zfs. Este es un sistema de archivos muy utilizado, tipo BTFRS. En el siguiente enlace podéis leer sobre sus ventajas. En mi caso crearé dos pools de datos. 1) un único disco M.2, para aplicaciones y volúmenes de docker. 2) dos discos mecánicos de 18 Tb, en espejo; es decir, con la información redundada.
Cabe señalar que estableceré una copia de seguridad diaria del servidor en el NAS, pero solo del disco del sistema y de 1). No copiaré 2) porque será un disco de descargas y por tanto de información transitoria que no pretendo conservar más allá de tener la redundancia en espejo que comento.
Para instalar zfs:
sudo apt-get -y install gdisk linux-headers-amd64 zfsutils-linux zfs-dkms zfs-zed
sudo reboot
6.1. - [opcional] Crear un pool de cero ↑
Si necesitamos crear los volúmenes desde cero haremos lo siguiente
¡Peligro, esto te elimina completamente la información de los discos! He puesto "DISCO1" hasta "DISCON" para que tengas que cambiarlo activamente. Ojo que perderás todo.
sudo sgdisk --zap-all /dev/DISCO1
sudo sgdisk --zap-all /dev/DISCON
Con los discos listos ya puedes crear un volumen (o pool). En la siguiente línea lo hacemos. Fíjate en el final de la línea. Al volúmen le llamaré "SERV-DATA", será una pool en espejo (básicamente una RAID 1) con los discos sda y sdb.
sudo zpool create -f -d -o ashift=12 -O atime=off -o feature@lz4_compress=enabled SERV-DATA mirror /dev/sda /dev/sdb
6.2. - Montar un volumen ↑
Y por último montamos los volúmenes que haya.
Si, independientemente de que hayas creado pools en el paso anterior, tienes pools creados previamente puedes listarlos mediante.
sudo zpool import
Imagen 2. Captura de pantalla con el listado de los pools zfs del sistema.
Solo queda cargar los pools creados. Una vez sabiendo su nombre haces (en mi caso mis pools son SERV-PROG y SERV-DATA):
sudo zpool import -f SERV-PROG
sudo zpool import -f SERV-DATA
Ahora puedes ver el status:
sudo zpool status
Imagen 3. Captura de pantalla con el estado de los pools zfs del sistema.
7. - Samba ↑
Para poder comunicarnos con facilidad en el entorno de red, instalaremos y configuraremos el protocolo samba:
sudo apt-get -y install samba smbclient cifs-utils
7.1. - Configurando las opciones globales de samba ↑
En el archivo
sudo nano /etc/samba/smb.conf
ponemos el work group correcto (yo uso desde hace años CLANDESTINE)
workgroup = CLANDESTINE
7.2. - Creando directorios compartidos Samba ↑
Crearemos un par de directorios, uno público y otro privado, dentro del pool de data:
sudo mkdir /SERV-DATA/public && sudo mkdir /SERV-DATA/private
En el archivo
sudo nano /etc/samba/smb.conf
Al final del archivo configuramos estos directorios que hemos creado
[public]
comment = Public Folder
path = /SERV-DATA/public
writable = yes
guest ok = yes
guest only = yes
force create mode = 775
force directory mode = 775
[private]
comment = Private Folder
path = /SERV-DATA/private
writable = yes
guest ok = no
valid users = @smbshare
force create mode = 770
force directory mode = 770
inherit permissions = yes
7.3. - Creando Samba share user y grupo ↑
Necesitamos un share user group para acceder a lo privado compartido, así que creamos el grupo y añadimos las carpetas previas a este grupo, dándoles los permisos adecuados
sudo groupadd smbshare
sudo chgrp -R smbshare /SERV-DATA/private/
sudo chgrp -R smbshare /SERV-DATA/public/
sudo chmod 2770 /SERV-DATA/private/
sudo chmod 2775 /SERV-DATA/public/
Lo siguiente es crear un user local sin login para acceder a la carpeta privada y lo añadimos al grupo que creamos antes.
sudo useradd -M -s /sbin/nologin sambauser
sudo usermod -aG smbshare sambauser
Ahora creamos una contraseña para el usuario y lo activamos
sudo smbpasswd -a sambauser
sudo smbpasswd -e sambauser
Y, por último, añadimos la regla al firewall y reiniciamos el servicio
sudo ufw allow from 192.168.1.0/24 to any app Samba
sudo systemctl restart nmbd
8. - Docker ↑
El último paso de esta guía es instalar docker. Como podéis ver, lo que hemos recorrido hasta ahora ha sido la configuración funcional del servidor, para poder trabajar con él. Docker será nuestro gestor de servicios. Es decir, todo lo que excede los servicios que hemos ido creando hasta ahora serán instanciados mediante docker. Esta configuración de docker comprende el tercer y último hilo de esta trilogía. Por lo pronto, instalemos y configuremos docker.
8.1. - Instalación de Docker ↑
Vamos a continuación a instalar Docker y Docker-Compose.
Lo primero que necesitamos es instalar el GPG key
# Add Docker's official GPG key:
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Con esto ya debería estar funcionando, podemos hacer un test mediante la línea
sudo docker run hello-world
Imagen 4. Captura de pantalla con la prueba de funcionamiento de docker. Este no es mal momento para incrementar la memoria virtual disponible para los contenedores. Para ello añadimos la línea vm.max_map_count=262144 en /etc/sysctl.conf y reiniciamos:
sudo echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
sudo reboot
8.2. - Docker rootless mode ↑
Uno de los objetivos de esta guía es hacer las cosas seguras (configuración de ssh, firewall, etc.). Como la mayoría de los microservicios los correremos a través de docker, y docker por defecto corre sobre root, desde hace un par de años existe la posibilidad de correr docker sin root, es decir docker rootless mode. Esto puede complicar el funcionamiento de algunas imágenes docker, pero es mucho más seguro. Si un microservicio se ve comprometido, complica mucho al atacante la escalada de privilegios en el host.
Para proceder con docker rootles, instalamos los siguientes paquetes
sudo apt-get install -y dbus-user-session fuse-overlayfs slirp4netns uidmap
Luego desactivamos el demonio de docker:
sudo systemctl disable --now docker.service docker.socket
A continuación instalamos docker rootless:
sudo apt-get install -y docker-ce-rootless-extras
/usr/bin/dockerd-rootless-setuptool.sh install
Una cosa interesante que podemos hacer es establecer que la gestión de logs la lleve el sistema, para ello:
mkdir ~/.config/docker && echo '{\n "log-driver": "journald"\n}' | tee -a ~/.config/docker/daemon.json
Es opcional, entonces, permitir que los puertos menores a 1024 puedan ser establecidos sin privilegios:
sudo setcap cap_net_bind_service=ep $(which rootlesskit)
systemctl --user restart docker
Para deshacer esto último:
sudo setcap cap_net_bind_service=-ep $(which rootlesskit)
systemctl --user restart docker
¡Con esto tenemos docker corriendo rootless! Fíjate en la siguiente captura, no necesitamos "sudo" para desplegar el hello-world. Nótese que no hemos añadido el usuario a un docker group o similar (cosa que puede crear brechas de seguridad).
Imagen 5. Captura de pantalla con la prueba de funcionamiento de rootless docker.
8.3. - Nvidia docker toolkit ↑
Ahora instalaremos la caja de herramientas de nvidia que permite comunicarse con docker. Configuramos el repositorio:
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
&& curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list \
&& \
sudo apt-get update
Y luego instalamos la herramienta
sudo apt-get install -y nvidia-container-toolkit
A continuación permitimos la ejecución rootless de nvidia, configuramos el runtime y reiniciamos el servicio docker
sudo sed -i 's/^#no-cgroups = false/no-cgroups = true/;' /etc/nvidia-container-runtime/config.toml
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
Con esto deberíamos tener la gráfica funcionando en docker. Testea con:
docker run --rm --gpus all debian nvidia-smi
Imagen 6. Captura de pantalla con la ejecución de nvidia-smi desde rootless docker.
9. Servidor DNS Pi-Hole ↑
Lo siguiente será instalar Pi-Hole, básicamente es un servidor DNS al que apuntarán nuestros dispositivos. De este modo podremos filtrar las peticiones a webs a nivel de red. Esto tiene efectos muy positivos, como que todas las peticiones contra la publicidad será bloqueada incluso antes de realizarse, por ejemplo
Instalar Pi-Hole es sencillo. Pipeamos a bash el script de instalación y seguimos los pasos:
curl -sSL https://install.pi-hole.net | sudo bash
Imagen 7. Captura de pantalla con la ejecución del instalador de pi-hole. Sigue los pasos de instalación al gusto y continuamos configurando. Una vez que esté instalado, lo que debemos hacer es que las DNS del servidor se apunten a sí mismo. Esto lo logramos editando el siguiente archivo:
sudo nano /etc/resolv.conf
Y cambiamos las ip que ahí aparecen a 127.0.0.1 Por último, el servicio DNS corre en el puerto 53, así que lo añadimos al firewall:
sudo ufw allow 53
Con esto ya tienes el servidor dando la configuración básica de DNS. Si quieres hacer cosas más chulas, como reglas y grupos de reglas a según qué usuario, deberás meterte más en profundidad. Esta es una buena fuente.
10. - Palabras finales ↑
¡Felicidades, ya tienes el servidor configurado! Muchas gracias por acompañarme hasta aquí. Tras la instalación del sistema, en este hilo hemos recorrido la configuración básica de un sistema operativo y sus dependencias para montar un homelab/servidor casero. Hemos preparado la configuración básica del sistema, luego una shell actual y cómoda, hemos instalado los drivers de nvidia para poder hacer funcionar cuda. Hemos instalado el sistema de archivos zfs y samba. Y, por último, hemos instalado docker de una forma segura. Mediante este hilo podéis seguir el discurso de pensamiento y acción que he llevado a la composición de mi homelab/servidor casero. Espero que os haya sido entretenido.
Imagen 8. Captura de pantalla con la entrada en el servidor una vez ya configurado.
10.1. - Para el futuro ↑
Ahora que ya tengo el servidor montado y estoy contento, tengo muchas ganas de hincharlo a microservicios. Lo cierto es que no pretendo hacer datahoarding y que los 18Tb en espejo debieran ser suficientes por lo pronto; pero no estaría mal proyectar cómo upgradear el juguete. Llevo ya un tiempo pensándolo y creo que mi siguiente paso sería adquirir un pequeño rack e ir montando todos los juguetes en él. Ahora el "barebone" NAS y su SAI, el SAI de mi ordenador de trabajo/servidor junto con el servidor en sí (que va en una ATX), y el hub, ocupan mucho espacio. Cuánto mejor montarlo todo ordenadito en rack, bien ventilado y con posibilidad de expandir con caddies para meter más discos duros, jeje.
10.2. - ¡Continúa con la serie! ↑
- El primer hilo trata sobre el hardware que he montado y por qué.
- (este) El segundo hilo trata sobre la configuración básica del sistema.
- El tercer hilo sobre microservicios personales para proyectos y jugueteos que me gustaría hacer.
Changelog ↑
- Versión 1.1R1 (27/04/2024)
- Versión 1.1R0 (12/12/2023)
- Corregidas un montón de erratas
- Añadido el comando para deshacer los privilegios para escuchar puertos bajos
- Añadida la instalación de Network Time Protocol
- Añadida la instalación y configuración de pi-hole
- Añadido Unattended-Upgrades
- Incrementada la memoria virtual de los contenedores
- Configurado docker para usar journald system
- Añadida una configuración de logrotate para traefik en avance
- Versión 1.0R1 (05/12/2023)
- Corregidas un montón de erratas
- Reformulación y explicación de parte de los procesos
- Versión 1.0R0 (04/12/2023)
- Versión inicial.
Esta obra está bajo una licencia Reconocimiento-No comercial 4.0 de Creative Commons. Para ver una copia de esta licencia, visite https://creativecommons.org/licenses/by-nc/4.0/deed.es o envíe una carta a Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.