--- weight: 4 title: "Apuntes de Proxmox VE" date: 2022-03-23T20:02:31+0100 draft: false summary: "Apuntes de Proxmox VE" categories: - notes tags: - proxmox - docker - traefik --- Estos apuntes son de _Proxmox VE_ un gestor de virtualizaciones muy potente implementado sobre Debian 11 Bullseye en la versión actual, la 7.1-11 en el momento de escribir esto. (Actualizado el 2022-03-23) # Proxmox VE _Promox VE_ es un software libre producto de _Proxmox Technologies_; una empresa austríaca que suministra productos de software libre (obvio). _Proxmox VE_, _Proxmox Backup Server_ y _Proxmox Mail Gateway_, como vemos en [su página web](https://www.proxmox.com) {{< admonition type=abstract title="Referencias" open=true >}} - [Blog de drivemeca](https://drivemeca.blogspot.com/2017/06/el-servidor-perfecto-proxmox-ve.html) {{< /admonition >}} ## Motivación Inicialmente configuré el mini-PC (Beelink Gemini T4) con Debian Server y Docker para poder implementar micro-servicios e instalar _Home Assistant_ (dockerizado). Como sentía curiosidad por ver como funciona la versión _Supervised_ de HAss (_Home Assistant_) empecé a mirar opciones para manejar máquinas virtuales en un servidor _headless_. Estudié la posibilidad de instalar Qemu, pero lo descarté por que tiene dependencias con Xorg que no me convencen. Varias personas me han hablado maravillas de _Proxmox_ y como tengo toda la instalación del mini-pc bien documentada y con copias de seguridad me he decidido a cambiar a _Proxmox_. Al fin y al cabo es saltar desde Debian a Debian con Proxmox, no debería ser muy traumático. ## Instalación de Proxmox Preparamos un USB con _Etcher_ con la ISO descargada de la [página web](https://www.proxmox.com/en/downloads) Arrancamos el minipc desde el USB (pulsando `F7`) y lanzamos la instalación. Durante la instalación sólo he tenido que configurar: __Parámetros de LVM__ El disco SSD del minipc es de 256Gb `Filesystem` : Escogemos `ext4` `hdsize` : Lo fija el instalador autmáticamente `swapsize` : Lo he fijado a 16Gb (creo que es mala idea en un SSD, si vemos que empieza a tirar de swap habrá que plantearse quitarla) `maxroot` : escogí 60Gb, este es el tamaño de la partición `root` que tendrá formato `ext4` `minfree` : la parte del disco que quedará disponible sin usar, he dejado reservados 60Gb `maxvz` : sería el límite máximo para el LVM `data` lo he puesto a 200 para que no limite, todo el disco menos los segmentos especificados en las opciones anteriores será usado para `data` __Parámetros de Red__ Especificamos la IP, el nombre del servidor (con dominio, aunque te lo puedes inventar claro) y el DNS __Timezone__ Especificamos en que zona horaria estamos. Con esto se completa la instalación y el sistema se reiniciará. Una vez reiniciado el sistema podremos conectarnos al PVE via web. También podemos conectarnos via _ssh_. Como tengo muchas claves generadas para distintas conexiones en mi ordenador, si nos conectamos sin más nos dará error de exceso de intentos (probará todas las claves). Para las primeras conexiones tendremos que usar: ```bash ssh -o PreferredAuthentications=password root@ 25 ``` ## Postinstalación Lo primero que tenemos que hacer, terminada la instalación es ajustar los orígenes del software y actualizar todos los paquetes. Es decir, lo que se hace siempre en una instalación de Debian. Cambiamos el origen de sw `pve-enterprise` por el `pve-no-subscription` (a menos que queramos alguna de las opciones de pago de _Proxmox_ que sería lo recomendable en un entorno de producción). Comentamos la linea en el fichero `/etc/apt/sources.list.d/pve-enterprise.list` Y creamos un nuevo fichero: ```bash echo "deb http://download.proxmox.com/debian/pve buster pve-no-subscription" > /etc/apt/sources.list.d/pve-no-suscription.list ``` En el fichero `/etc/apt/sources.list` cambiamos los orígenes de software de Debian, e incluimos `contrib` y `non-free`: ```bash deb http://deb.debian.org/debian/ buster main contrib non-free deb-src http://deb.debian.org/debian/ buster main contrib non-free deb http://security.debian.org/debian-security buster/updates main contrib non-free deb-src http://security.debian.org/debian-security buster/updates main contrib non-free # buster-updates, previously known as 'volatile' deb http://deb.debian.org/debian/ buster-updates main contrib non-free deb-src http://deb.debian.org/debian/ buster-updates main contrib non-free ``` Actualizamos todos los paquetes con: ```bash apt update apt upgrade ``` Podemos actualizar todos los paquetes de _Proxmox_ con el comando `pveam update`, o hacerlo desde el interfaz gráfico, que es más ilustrativo para las primeras veces (lo vemos luego) Una vez actualizado el sistema operativo procedemos a instalar nuestros paquetes habituales. ### Instalamos _git_ y _etckeeper_ Suelo instalar _etckeeper_ para tener un histórico automático de cambios en el `/etc` Como `root` ejecutamos: ```bash apt install git git config --global user.email "whaterver@mail.com" git config --global user.name "Name Surname" apt install etckeeper ``` Si quieres ver el histórico de cambios de `/etc` solo tienes que ejecutar como `root`: ```bash cd /etc git log ``` {{< admonition type=tip title="Problemas con default locales" open=false >}} Si (como a mi) te dan problemas los `locales` (suele pasar en la instalación de _Debian Server_ veras que `apt` y `apt-get` protestan por la configuración de `locales`) se puede arreglar fácilmente sin más que ejecutar `sudo dpkg-reconfigure locales` Puedes aprovechar la ejecución para dejar generado algún `locale` adicional. Estos son los que yo he dejado configurados en mi server (se pueden consultar con el comando `locale`): ```bash ## Antes de la reconfiguración LANGUAGE = (unset), LC_ALL = (unset), LC_MONETARY = "es_ES.UTF-8", LC_ADDRESS = "es_ES.UTF-8", LC_TELEPHONE = "es_ES.UTF-8", LC_NAME = "es_ES.UTF-8", LC_MEASUREMENT = "es_ES.UTF-8", LC_IDENTIFICATION = "es_ES.UTF-8", LC_NUMERIC = "es_ES.UTF-8", LC_PAPER = "es_ES.UTF-8", LANG = "en_US.UTF-8" ## Después de la reconfiguración LANG=en_US.UTF-8 LANGUAGE= LC_CTYPE="en_US.UTF-8" LC_NUMERIC=es_ES.UTF-8 LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY=es_ES.UTF-8 LC_MESSAGES="en_US.UTF-8" LC_PAPER=es_ES.UTF-8 LC_NAME=es_ES.UTF-8 LC_ADDRESS=es_ES.UTF-8 LC_TELEPHONE=es_ES.UTF-8 LC_MEASUREMENT=es_ES.UTF-8 LC_IDENTIFICATION=es_ES.UTF-8 LC_ALL= ``` {{< /admonition >}} ### Varios programas instalados en Debian 10 ---- __OJO__: `apt` instala por defecto los paquetes recomendados, si no quieres que eso ocurra usa `apt-get` o `aptitude` con las opciones correspondientes. ---- Instalamos varias librerías de compresión: ```bash apt install rar unrar zip unzip unace bzip2 lzop p7zip p7zip-full ``` Instalamos algunas utilidades: ```bash apt install most mc tree neofetch tmux aptitude htop ``` Instalamos sudo: ```bash apt install sudo ``` Cualquier usuario que pertenezca al grupo `sudo` podrá ejecutar comandos con privilegios de _root_. (podemos añadirlos, por ejemplo, con `gpasswd -a sudo`) ### Configuramos el acceso via _ssh_ El PVE incluye su propio cortafuegos. Tendremos que revisar su configuración más tarde. #### Creamos un usuario de administración Me voy a crear un usuario de administración para no tener que hacer login con `root`. El usuario va a estar en el grupo `sudo` así que va a ser todopoderoso, pero tendrá que saber su password para poder "sudar". ```bash # sudo adduser administrator # sudo gpasswd -a administrator sudo $ adduser --uid=1111 hostadmin gpasswd -a hostadmin sudo ``` #### Parámetros de login _ssh_ Vamos a: * Deshabilitar el login de root via ssh (queremos que todos entren con su usuario persona y después usen sudo) * Deshabilitar el login con contraseña (queremos que todo el mundo use autenticación por clave pública) Lo primero de todo es configurar y probar nuestro acceso con clave ssh, copiamos nuestra clave al servidor, debemos copiarla tanto para el usuario `root` como para el usuario administrador que hayamos creado: `ssh-copy-id -o IdentitiesOnly=yes -i ~/.ssh/mykey.pub @` Y probamos a conectarnos con la clave. `ssh -i ~/.ssh/mykey @` Si todo va bien podemos añadir (en nuestro pc, no en el servidor _Proxmox_) la información de conexión a nuestro fichero `~/.ssh/config` ```cfg Host HostName User Port 22 IdentityFile ~/.ssh/ ``` El fichero que controla la configuración del demonio _ssh_ en nuestro servidor es `/etc/ssh/sshd_config` tenemos que asegurarnos de añadir las siguientes lineas: ```cfg PermitRootLogin no PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no ``` Después de cambiar la configuración reiniciamos el servicio con `sudo systemctl restart ssh` Tras el reinicio no deberíamos poder hacer login con `root` via ssh. #### _ssh-agent_ Esto es un apunte uso para trabajar cómodo con Gitlab desde el servidor _Proxmox_, con las claves _ssh_ instaladas en el servidor. ```bash eval `ssh-agent` ssh-add .ssh/dev_rsa ssh-add -l ssh-add -L ``` ### Disco duro interno {{< admonition type=info title="Referencias de HDD" open=false >}} - [Opciones para `ext4`](https://man7.org/linux/man-pages/man5/ext4.5.html) - [Un buen resumen](https://www.howtogeek.com/444814/how-to-write-an-fstab-file-on-linux/) - [Filtrar discos del LVM](https://forum.proxmox.com/threads/disk-prevent-from-spinning-down-because-of-pvestatd.53237/) - [Crear un servicio systemd con las optimizaciones](https://unix.stackexchange.com/questions/80437/how-can-i-run-an-hdparm-command-after-boot-and-resume-on-fedora-19) {{< /admonition >}} En mi caso el disco duro interno que quiero añadir está mapeado en `/dev/sda`, se trata de un disco de 2Tb y queremos hacer dos particiones: una para almacenar backups, templates, snapshots, etc. etc. Y otra partición (mucho más grande) que usaremos para crear discos para las VM. Con nuestro programa de particionado favorito creamos las dos particiones. Yo tengo disponibles `fdisk` y `parted` pero nada impide instalar el que nos guste. He creado una partición de 250 Gb para almacenamiento y el resto de la capacidad para discos de VM. #### Creando el "directorio" Navegamos hasta nuestra máquina host debajo del `Datacenter` localizamos el interfaz `Disks::Directory` y creamos el nuevo directorio apuntando a la partición que hemos creado en el paso anterior (`/dev/sda1` en mi caso), con el sistema de ficheros que nos guste (lo he dejado como ext4) y le damos un nombre descriptivo (para mi `hdd_directory`). #### Creado el volumen lógico Navegamos a `LVM` debe estar muy cerca, por encima de `Directory`. Seleccionamos el botón `Create Volume Group`: sólo tenemos que especificar la partición a utilizar y un nombre. Y eso es todo ya tenemos un VG donde podremos crear discos para nuestras máquinas virtuales. ### Discos duros USB externos Si son discos nuevos ejecutamos estos pasos 1. Conectamos los discos al mini-pc 1. Comprobamos los discos con `lsblk -p |grep disk` o con `sudo fdisk -l` 1. Si es necesario los podemos formatear a _ext4_ con el comando `sudo mkfs.ext4 /dev/sdX` (donde X será la letra que corresponda a nuestros discos) 1. Creamos el/los puntos de montaje de nuestros discos, p.ej. `/mnt/usbA`, con el comando `sudo mkdir /mnt/usbA` 1. Montamos el/los discos con el comando `sudo mount /dev/sdX /mnt/usbA` Para dejar los discos duros mapeado permanentemente en nuestro servidor debemos modificar el fichero `/etc/fstab`: 1. Averiguamos la identidad de los discos con `sudo blkid` 2. Añadimos las lineas correspondientes al fichero `/etc/fstab` que serán de esta forma (cambia los UUID): ```fstab UUID=1a716b79-b39a-49bf-bae6-4992376022e0 /mnt/usbA ext4 defaults 0 2 ``` #### Discos duros externos que no dejan de funcionar Mis discos duros externos son un par de discos USB portátiles, dudo mucho que puedan estar funcionando continuamente. _Proxmox_ escanea continuamente todos los discos duros del sistema. Si queremos que los discos duros se duerman tenemos que cambiar la configuración en el fichero `/etc/lvm/lvm.conf`. Concretamente cambiamos la linea: `global_filter = [ "r|/dev/sd(b|c)|" , "r|/dev/zd.*|", "r|/dev/mapper/pve-.*|" "r|/dev/mapper/.*-(vm|base)--[0-9]+--disk--[0-9]+|"]` Con la primera entrada (`"r|/dev/sd(b|c)|"`) estamos indicando que se ignore los discos `/dev/sdb` y `/dev/sdc`. Con esto perdemos también la posibilidad de crear volúmenes _lvm_ en estos discos, pero a mi de momento no me interesa. -------------------- ### _dynhost_ en OVH Instalado [el script de actualización de dynhost](https://github.com/BorisPAING/dynhost-ovh) en OVH. Es necesario tener disponible `dig` así que instalamos: ```bash sudo apt install dnsutils ``` Después basta con programar el *script* periódicamente en el crontab de `root` con las credenciales de OVH. ### Comprobamos la instalación de python ```bash apt install python-all-dev python3-all-dev apt install virtualenv python3-virtualenv virtualenvwrapper ``` ### Instalado el zsh Lo he dejado instalado siguiendo [la guía](https://gitlab.com/salvari/linuxmint_ulyana_20). ## Revisión de la instalación de Proxmox * Nos conectamos al interfaz web con el usuario `root` y la contraseña que hemos establecido durante la instalación. * Clicamos en nuestro nodo (el servidor en el árbol de la izquierda) y comprobamos las actualizaciones pendientes (_Updates_) ## Instalación de una máquina virtual con Home Assistant {{< admonition type=info title="Referencias" open=false >}} - [Install HAss on Proxmox](https://community.home-assistant.io/t/installing-home-assistant-os-using-proxmox-7/201835) (by Kanga-Who) {{< /admonition >}} Una de las misiones principales de mi servidor Proxmox es soportar la VM de Homeassistant. Crear la máquina virtual es muy fácil gracias a los scripts creados por _Whiskerz007_ y _Kanga-Who_. Vamos a seguir la página de este último. Antes de arrancar la VM conviene revisar el hardware asignado y las opciones de la VM (yo solo tuve que ajustar la memoria asignada) ## Instalación de Docker {{< admonition type=info title="Referencias" open=false >}} - [Running Docker on Proxmox](https://danthesalmon.com/running-docker-on-proxmox/) {{< /admonition >}} Tendríamos tres formas de instalar Docker en nuestro sistema _Proxmox_ - Instalándolo en el S.O. Debian base - Como contenedor LXC - Como máquina virtual Mi intención era usar el primer método e instalar el _Docker_ sobre Debian. Este método no debería usarse nunca en producción pero para el uso que yo quiero darle parece aceptable. Lo he instalado aunque, de momento, dejo el servicio _Docker_ desactivado. El segundo método que he usado es crear una máquina virtual con _Alpine Linux_ e instalar _Docker_ sobre esa máquina. ### Instalar Docker en Debian Vamos allá ```bash apt update apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 7EA0A9C3F273FCD8 apt update apt-cache policy docker-ce apt install docker-ce systemctl status docker gpasswd -a username docker ``` Y ya tenemos docker instalado. Ahora completamos con la instalación de _docker-compose_. Primero comprobamos la versión. En el momento de escribir esto es la 1.28.5. Con el siguiente comando descargamos el binario correspondiente a nuestro sistema en `/usr/local/bin` y le damos permisos de ejecución. ```bash curl -L https://github.com/docker/compose/releases/download/1.28.5/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose ``` Para parar el servicio _Docker_ y dejarlo desactivado (con los alias de zsh): ```bash scs docker # systemctl status docker scsp docker # systemctl stop docker scd docker # systemctl disable docker scs docker # systemctl status docker ``` ### Instalar Docker en una máquina virtual {{< admonition type=info title="Referencias" open=false >}} - [How to install docker on Alpine Linux VM](https://nubcakes.net/index.php/2019/03/15/how-to-install-docker-on-alpine-linux-vm/) - [How to install Docker CE on Alpine Linux](https://www.how2shout.com/how-to/how-to-install-docker-ce-on-alpine-linux.html) - [Alpine Linux Wiki: Docker](https://wiki.alpinelinux.org/wiki/Docker) - [Howto Alpine Wall](https://wiki.alpinelinux.org/wiki/How-To_Alpine_Wall) {{< /admonition >}} * Descargamos la imagen ISO de Alpine optimizada para sistemas virtuales desde [aquí](https://alpinelinux.org/downloads/) * Subimos la imagen ISO a nuestro nodo en _Proxmox_ (En el árbol vamos a: __nodo → local(nodo) → Iso Images__) * Creamos una máquina virtual (he dejado prácticamente los valores por defecto, asignando 32Gb de disco duro) * Una vez arrancada la máquina ejecutamos `setup-alpine` y vamos asignando las [opciones de instalación](https://wiki.alpinelinux.org/wiki/Installation#Questions_asked_by_setup-alpine): * Teclado `es-winkeys` * Hostname: `srvname` * Asignamos IP estática * Es necesario tener acceso a internet para asignar los repos de software de Alpine, así que hay que asignar _gateway_ y _dns server_. * Escogemos "sys" para la estructura de disco * Damos permiso para usar y borrar el disco Una vez instalado y rearrancado el sistema editamos `/etc/apk/repositories` y habilitamos `comunity`. __¡Ojo!__ si habilitas `edge` estarás habilitando la rama de desarrollo de Alpine y no es lo que queremos ahora mismo. Actualizamos los paquetes del sistema con `apk update`. Instalamos `apk add qemu-guest-agent` {{< admonition type=info title="Qemu-guest-agent" open=true >}} El _qemu-guest-agent_ sirve para que _Proxmox_ pueda parar la VM y/o congelar su sistema de ficheros de forma segura. Esto facilita mucho varias operaciones como por ejemplo hacer _backups_ de las VM {{< /admonition >}} Editamos el fichero `/etc/init-d/qemu-guest-agent`, su última línea tiene que ser: `command_args="-m ${GA_METHOD:-virtio-serial} -p ${GA_PATH:-/dev/vport2p1} -l /var/log/qemu-ga.log -d"` Añadimos el agente al arranque: `rc-update add qemu-guest-agent boot` Paramos la máquina virtual y en el interfaz _Proxmox_ cambiamos las opciones para habilitar el `Qemu Guest Agent` Volvemos a arrancar la VM (Importante reiniciar desde el Proxmox) y comprobamos que en el `Summary` el `qemu-guest-agent` se conecta correctamente. {{< admonition type=warning title="Qemu-guest-agent: fallo al crear el canal" open=false >}} Mi `qemu-guest-agent` fallaba al arrancar con los siguientes mensajes en `/var/log/qemu-ga.log` ```log 1618081791.809004: critical: error opening channel: No such file or directory 1618081791.809056: critical: error opening channel 1618081791.809070: critical: failed to create guest agent channel 1618081791.809082: critical: failed to initialize guest agent channel ``` Por alguna razón la máquina que he creado no tiene el dispositivo `/dev/vport1p1`. El dispositivo en mi máquina es el `/dev/vport2p1`. Evidentemente el agente falla hasta que corregimos el fichero `/etc/init-d/qemu-guest-agent` {{< /admonition >}} A continuación procedemos a instalar `sudo` con `apk add sudo` y con `visudo` habilitamos sudo para el grupo `wheel` (descomentar la linea correspondiente) Creamos grupo y usuario para _Docker_: ```bash addgroup -g 150 docker addgroup dockadmin adduser -G dockadmin dockadmin adduser dockadmin wheel adduser dockadmin docker cat /etc/passwd ``` Instalamos _Docker_: ```bash apk add docker rc-update add docker boot service docker start service docker status ``` Y lo probamos: `docker run --rm hello-world` Como todo va bien instalamos también el `docker-compose` ```bash sudo apk add docker-compose ``` #### Cortafuegos Instalamos el UFW ```bash sudo apk add ufw ``` Y hacemos una configuración inicial ```bash sudo ufw status verbose # Comprobamos que está deshabilitado sudo ufw app list # comprobamos que apps soporta sudo ufw default deny incoming # le decimos que por defecto no acepta nada entrante sudo ufw default allow outgoing # por defecto permitimos conexiones salientes sudo ufw allow ssh # permitimos conexiones ssh sudo ufw enable # lo habilitamos sudo ufw status verbose # vemos el estado del cortafuegos ``` #### Instalando nuestros primeros contenedores Una vez comprobado que funciona todo añadimos una configuración básica con _Traefik_ y _Portainer_ como comentamos en [el ejemplo 3 de los apuntes de _Traefik_]({{< ref "notes_traefik/#ejemplo03-una-configuraci%C3%B3n-sencilla-para-empezar-con-traefik-en-producci%C3%B3n" >}}) #### Almacenamiento para Docker * [Referencia](https://www.hiroom2.com/2018/08/29/alpinelinux-3-8-sshfs-en/) Como hemos sacado los discos duros externos del Proxmox no podemos crear volúmenes en los mismos. Para darle espacio de almacenamiento a los contenedores en esos discos duros vamos a hacer algo un poco rebuscado: montar un directorio del disco externo via `sshfs`. En nuestra máquina virtual Alpine: 1. Instalamos los paquetes `sshfs` y `util-linux`, además configuramos el sistema para que se carge el módulo del kernel `fuse` ```bash sudo apk add sshfs util-linux sudo modprobe fuse echo fuse | sudo tee -a /etc/modules ``` 2. Creamos el directorio local (en nuestra VM) donde montaremos el disco duro externo. ```bash mkdir $HOME/mnt/store ``` 3. Creamos una clave con `ssh-keygen` que nos permita facilitar la conexión a la máquina virtual. Una vez creada la clave , podriamos crear el fichero `~/.ssh/config` y montar la unidad por comando con el usuario administrador de docker (por ejemplo). Pero nos interesa más montar el directorio del disco duro en el arranque de la máquina virtual dejándolo especificado en el fichero `/etc/fstab` Generalmente no permitimos el acceso del usuario `root` via ssh en ningún sistema, así que tendremos que especificar el montaje con un usuario. Usaremos el usuarios `dockadmin` del servidor host y el usuario del mismo nombre que creamos en la máquina virtual de Docker. 4. Añadimos la clave pública al fichero `~/.ssh/authorized_keys` del usuario `dockadmin` en la VM. (depende de tu escenario, yo lo hice pasando por mi ordenador personal, desde donde estoy configurando todo) 5. Creamos una entrada para la VM en el fichero `/etc/hosts` ```bash sudo echo " hostname" >> /etc/hosts ``` 6. Habilitamos `netmount` ```bash sudo rc-update add netmount ``` 7. Añadimos la linea al fichero `/etc/fstab` ```fstab dockadmin@sirio:/mnt/usbA/Work/dockerStore:/home/dockadmin/mnt/store fuse.sshfs _netdev,identityfile=/home/dockadmin/.ssh/id_mount,allow_other,uid=dockeradmin,gid=dockeradmin 0 0 ``` ## Recetillas ### Quitando el mensaje de "invalid subscription" {{< admonition type=info title="Referencia" open=false >}} - [Remove Proxmox subscription warning](https://johnscs.com/remove-proxmox51-subscription-notice/) {{< /admonition >}} Editamos el fichero `/usr/share/javascript/proxmox-widget-toolkit/promoxlib.js` Localizamos la cadena `No valid subscription` y cambiamos al función para que quede así: ```javascript void({ //Ext.Msg.show({ title: gettext('No valid subscription'), ``` Reiniciamos el servicio con `systemctl restart pveproxy.service`