{"id":2542,"date":"2025-12-01T20:47:36","date_gmt":"2025-12-01T20:47:36","guid":{"rendered":"https:\/\/garikoitz.info\/blog\/?p=2542"},"modified":"2025-12-19T18:14:40","modified_gmt":"2025-12-19T18:14:40","slug":"de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica","status":"publish","type":"post","link":"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/","title":{"rendered":"De un VPS comercial al sal\u00f3n de casa. Parte 3 \u2013 Configuraci\u00f3n b\u00e1sica"},"content":{"rendered":"\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">\u00cdndice<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Alternar tabla de contenidos\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 eztoc-toggle-hide-by-default' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Intro\" >Intro<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Requisitos\" >Requisitos<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Configuracion_de_DuckDNS_en_la_Raspberry_Pi\" >Configuraci\u00f3n de DuckDNS en la Raspberry Pi<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Instalacion_de_software_base\" >Instalaci\u00f3n de software base<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Archivos_y_rutas_relevantes\" >Archivos y rutas relevantes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Comprobaciones_finales\" >Comprobaciones finales<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Configuracion_del_Firewall\" >Configuraci\u00f3n del Firewall<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Configuracion_del_correo\" >Configuraci\u00f3n del correo<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Gmail_como_servidor_de_correo\" >Gmail como servidor de correo<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/#Postfix_Brevo\" >Postfix + Brevo<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Intro\"><\/span>Intro<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Voy a omitir la instalaci\u00f3n de Raspberry PI OS en la microSD. Dispon\u00e9is de cientos de videos y art\u00edculos al respecto y es por ello que me voy a centrar en los paquetes de software y comandos que considero m\u00e1s importantes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Requisitos\"><\/span>Requisitos<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Raspberry Pi con Raspberry Pi OS \/ Debian 12<\/li>\n\n\n\n<li>Acceso a Internet<\/li>\n\n\n\n<li>IP p\u00fablica o servicio DDNS (por ejemplo, DuckDNS)<\/li>\n\n\n\n<li>Puertos <strong>80<\/strong> y <strong>443<\/strong> abiertos en el router y redirigidos a la IP local de la Raspberry<\/li>\n\n\n\n<li>Uno o varios dominios registrados (ej.: <code>midominio.com<\/code>)<\/li>\n\n\n\n<li><strong>Cuenta en DuckDNS y subdominio creado<\/strong> (ej.: <code>tuhost.duckdns.org<\/code>)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configuracion_de_DuckDNS_en_la_Raspberry_Pi\"><\/span>Configuraci\u00f3n de DuckDNS en la Raspberry Pi<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 1. Crear cuenta y subdominio en DuckDNS\n#    - Acceder a https:\/\/www.duckdns.org  \n#    - Iniciar sesi\u00f3n con GitHub, Google u otra cuenta compatible  \n#    - Crear un subdominio (por ejemplo: `tuhost.duckdns.org`)  \n#    - Copiar el **Token** asignado a la cuenta\n\n# 2. Crear script de actualizaci\u00f3n DDNS\n# crear un directorio para DuckDNS:\nmkdir -p ~\/duckdns\ncd ~\/duckdns\n\n# crear el archivo duck.sh (Recuerda: en nano copia el script y CTRL+O y enter para guardar y CTRL+X para salir)\nsudo nano duck.sh<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\necho url=\"https:\/\/www.duckdns.org\/update?domains=tuhost&amp;token=TU_TOKEN&amp;ip=\" \\\n| curl -k -o ~\/duckdns\/duck.log -K -<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># sustituir tuhost por el subdominio creado y TU_TOKEN por el token de DuckDNS\n\n# dar permiso de ejecuci\u00f3n\nsudo chmod +x duck.sh\n\n# 3. Programar la actualizaci\u00f3n autom\u00e1tica\ncrontab -e\n\n# A\u00f1adir la siguiente l\u00ednea para actualizar la IP cada 5 minutos:\n*\/5 * * * * ~\/duckdns\/duck.sh >\/dev\/null 2>&amp;1\n\n# (Recuerda: CTRL+O y enter para guardar y CTRL+X para salir)\n\n# 4. Verificaci\u00f3n del funcionamiento\n~\/duckdns\/duck.sh\ncat ~\/duckdns\/duck.log\n\n# Si la respuesta contiene OK, la actualizaci\u00f3n se ha realizado correctamente.<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Instalacion_de_software_base\"><\/span>Instalaci\u00f3n de software base<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 1. Actualizar el sistema\nsudo apt update &amp;&amp; sudo apt upgrade -y\n\n# 2. Instalar servicios base\nsudo apt install nginx mariadb-server php php-fpm php-mysql unzip curl -y\n\n# 3. Verificar instalaci\u00f3n\nphp -v\nnginx -t\n\n# 4. Crear estructura de directorios del dominio\n#    (usuario ser\u00e1 el usuario con el que se suben archivos por SFTP\/SSH)\nsudo mkdir -p \/var\/www\/midominio.com\/html\necho \"&lt;h1>midominio.com funcionando&lt;\/h1>\" | sudo tee \/var\/www\/midominio.com\/html\/index.html\nsudo chown -R usuario:www-data \/var\/www\/midominio.com\nsudo chmod -R 775 \/var\/www\/midominio.com\n\n# 5. Crear configuraci\u00f3n nginx (VirtualHost)\n#    (Recuerda: en nano copia el script y CTRL+O y enter para guardar y CTRL+X para salir)\nsudo nano \/etc\/nginx\/sites-available\/midominio.com<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">server {\n    listen 80;\n    server_name midominio.com www.midominio.com;\n\n    root \/var\/www\/midominio.com\/html;\n    index index.php index.html index.htm;\n\n    access_log \/var\/log\/nginx\/midominio.com.access.log;\n    error_log  \/var\/log\/nginx\/midominio.com.error.log;\n\n    location \/ {\n        try_files $uri $uri\/ =404;\n    }\n\n    location ~ \\.php$ {\n        include snippets\/fastcgi-php.conf;\n        fastcgi_pass unix:\/run\/php\/php8.2-fpm.sock;\n    }\n\n    location ~ \/\\.ht {\n        deny all;\n    }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 6. Activar el sitio\nsudo ln -s \/etc\/nginx\/sites-available\/midominio.com \/etc\/nginx\/sites-enabled\/\nsudo nginx -t\nsudo systemctl reload nginx\n\n# 7. Configuraci\u00f3n DNS del dominio (dynadot, namecheap, arsys, nominalia...) con DDNS (DuckDNS por ejemplo)\nTipo CNAME\n@     \u2192 tuhost.duckdns.org\nwww   \u2192 tuhost.duckdns.org\n\n# 8. Habilitar HTTPS con Let\u2019s Encrypt\nsudo apt install certbot python3-certbot-nginx -y\n\n# 8.1 Solicitar certificado\nsudo certbot --nginx -d midominio.com -d www.midominio.com\n\n# 9. Renovaci\u00f3n autom\u00e1tica de certificados\nsystemctl list-timers | grep certbot\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Archivos_y_rutas_relevantes\"><\/span>Archivos y rutas relevantes<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Ruta<\/th><th>Descripci\u00f3n<\/th><\/tr><\/thead><tbody><tr><td><code>\/var\/www\/midominio.com\/html\/<\/code><\/td><td>Web ra\u00edz del dominio<\/td><\/tr><tr><td><code>\/etc\/nginx\/sites-available\/midominio.com<\/code><\/td><td>VirtualHost nginx<\/td><\/tr><tr><td><code>\/etc\/nginx\/sites-enabled\/midominio.com<\/code><\/td><td>Enlace activo<\/td><\/tr><tr><td><code>\/var\/log\/nginx\/midominio.com.access.log<\/code><\/td><td>Log de accesos<\/td><\/tr><tr><td><code>\/var\/log\/nginx\/midominio.com.error.log<\/code><\/td><td>Log de errores<\/td><\/tr><tr><td><code>\/etc\/letsencrypt\/<\/code><\/td><td>Certificados SSL<\/td><\/tr><tr><td><code>\/etc\/hosts<\/code> (opcional)<\/td><td>Resoluci\u00f3n local de dominios<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Comprobaciones_finales\"><\/span>Comprobaciones finales<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Una vez completada la instalaci\u00f3n y configuraci\u00f3n del servidor, se debe comprobar que el acceso al dominio funciona correctamente tanto desde el exterior como desde la red local. En primer lugar, se accede desde un navegador a <code>https:\/\/midominio.com<\/code> para verificar que nginx responde correctamente y que el certificado SSL es v\u00e1lido. A continuaci\u00f3n, se comprueba la subida y modificaci\u00f3n de archivos mediante SFTP o SSH con el usuario configurado, confirmando que los cambios se reflejan en el navegador. Tambi\u00e9n es recomendable revisar los registros de acceso y errores de nginx para asegurar que no existen incidencias inesperadas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para el acceso <strong>desde la red local<\/strong>, cuando el router no soporta NAT loopback o el dominio no resuelve internamente a la IP privada de la Raspberry Pi, es necesario modificar el archivo de resoluci\u00f3n de nombres del sistema operativo cliente. En <strong>Windows<\/strong>, esto se realiza editando el archivo <code>hosts<\/code> ubicado en <code>C:\\Windows\\System32\\drivers\\etc\\hosts<\/code>, a\u00f1adiendo una l\u00ednea que asocie la IP local de la Raspberry Pi con el dominio, por ejemplo <code>192.168.2.160 midominio.com www.midominio.com<\/code>. En <strong>Linux<\/strong>, el procedimiento es equivalente, editando el archivo <code>\/etc\/hosts<\/code> con permisos de root y a\u00f1adiendo la misma correspondencia. De este modo, los equipos de la red local podr\u00e1n acceder al servidor utilizando el nombre de dominio como si se tratase de un acceso externo. Desde dispositivos Android e IOS lo m\u00e1s sencillo es desconectarse del wifi y acceder desde el exterior (4G, 5G).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configuracion_del_Firewall\"><\/span>Configuraci\u00f3n del Firewall<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">En sistemas Linux actuales, el filtrado de red se realiza mediante <strong>nftables<\/strong>, que sustituye a iptables como cortafuegos del kernel.<br><strong>Fail2Ban<\/strong> se integra directamente con nftables para aplicar bloqueos din\u00e1micos basados en el an\u00e1lisis de los registros del sistema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La configuraci\u00f3n m\u00ednima consiste en:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Instalar y habilitar Fail2Ban<\/strong> como servicio del sistema.<\/li>\n\n\n\n<li>Definir un archivo <code>jail.local<\/code> con valores globales sencillos:\n<ul class=\"wp-block-list\">\n<li>Tiempo de baneo (<code>bantime<\/code>)<\/li>\n\n\n\n<li>Ventana de an\u00e1lisis (<code>findtime<\/code>)<\/li>\n\n\n\n<li>N\u00famero m\u00e1ximo de intentos fallidos (<code>maxretry<\/code>)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Excluir direcciones locales y redes privadas mediante <code>ignoreip<\/code>, evitando autobaneos.<\/li>\n\n\n\n<li>Activar \u00fanicamente los jails necesarios:\n<ul class=\"wp-block-list\">\n<li><code>sshd<\/code> para proteger el acceso por SSH.<\/li>\n\n\n\n<li>Jails de nginx para detectar autenticaciones fallidas y escaneos autom\u00e1ticos.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Cuando Fail2Ban detecta un comportamiento sospechoso en los logs, a\u00f1ade la IP atacante a un <strong>set de nftables<\/strong>, bloque\u00e1ndola directamente en el kernel.<br>No se crean reglas complejas ni cadenas manuales: el bloqueo es inmediato, eficiente y reversible.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">## Resumen de comandos fail2ban+nftables (seguridad m\u00ednima)\n\n# 1. Instalar fail2ban\nsudo apt update\nsudo apt install -y fail2ban\n\n# 2. Editar jail.local\nsudo nano \/etc\/fail2ban\/jail.local<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># contenido de \/etc\/fail2ban\/jail.local\n\n[DEFAULT]\nbantime  = 1h\nfindtime = 10m\nmaxretry = 5\nbackend  = systemd\nignoreip = 127.0.0.1\/8 192.168.0.0\/16\n\n[sshd]\nenabled = true\nport    = ssh\nlogpath = %(sshd_log)s\n\n[nginx-http-auth]\nenabled = true\nport    = http,https\nlogpath = \/var\/log\/nginx\/error.log\n\n[nginx-botsearch]\nenabled = true\nport    = http,https\nlogpath = \/var\/log\/nginx\/access.log\n\n[nginx-badbots]\nenabled = true\nport    = http,https\nlogpath = \/var\/log\/nginx\/access.log<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">* Aqu\u00ed estamos configurando excepci\u00f3n de baneos para localhost (127.0.0.1) y para nuestra red local (192.168.0.0 &#8211; 192.168.255.255). Debes adaptar estas IPs a tu red local.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 3. Comprobar configuraci\u00f3n\nsudo fail2ban-client -t\n\n# 4. Reiniciar y habilitar\nsudo systemctl restart fail2ban\nsudo systemctl enable fail2ban\n\n#\n#Comandos \u00fatiles\n#\n\n# Ver estado general\nsudo fail2ban-client status\n\n# Ver estado de un jail\nsudo fail2ban-client status sshd\nsudo fail2ban-client status nginx-botsearch\n\n# Ver IPs baneadas\nsudo fail2ban-client get sshd banip\n\n# Desbanear una IP\nsudo fail2ban-client set sshd unbanip X.X.X.X\n\n# Limpiar todos los baneos\nsudo fail2ban-client unban --all\n\n# Ver logs de fail2ban\nsudo journalctl -u fail2ban --no-pager\nsudo tail -f \/var\/log\/fail2ban.log<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configuracion_del_correo\"><\/span>Configuraci\u00f3n del correo<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Gmail_como_servidor_de_correo\"><\/span>Gmail como servidor de correo<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">La configuraci\u00f3n basada en el uso de una cuenta de Gmail como servidor de env\u00edo \u2014mediante la denominada \u201caplicaci\u00f3n Gmail\u201d o SMTP de Google\u2014 presenta importantes limitaciones cuando se emplea en foros o aplicaciones con un volumen m\u00ednimo de correos. Gmail impone l\u00edmites diarios estrictos de env\u00edo, controles de frecuencia y pol\u00edticas cada vez m\u00e1s severas contra el uso automatizado, lo que provoca bloqueos temporales, retrasos o la no entrega de mensajes cr\u00edticos como recuperaciones de contrase\u00f1a. Adem\u00e1s, el uso de credenciales personales o contrase\u00f1as de aplicaci\u00f3n implica un mayor riesgo de seguridad y una dependencia directa de la cuenta del administrador. A todo ello se suma que Gmail no est\u00e1 dise\u00f1ado como plataforma de correo transaccional, por lo que carece de herramientas adecuadas de seguimiento, gesti\u00f3n de reputaci\u00f3n y control de entregabilidad, haciendo que esta opci\u00f3n resulte poco adecuada y dif\u00edcilmente escalable para entornos de producci\u00f3n, incluso en instalaciones dom\u00e9sticas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Aun as\u00ed, si se desea utilizar este m\u00e9todo, es necesario acceder a la cuenta de Google, entrar en el apartado de <strong>Seguridad<\/strong>, activar la verificaci\u00f3n en dos pasos y generar una <strong>contrase\u00f1a de aplicaci\u00f3n<\/strong>, que ser\u00e1 la utilizada por el servidor o la aplicaci\u00f3n. Finalmente, en la propia aplicaci\u00f3n se debe configurar el env\u00edo SMTP apuntando a <code>smtp.gmail.com<\/code>, habitualmente por el puerto 587 con TLS, indicando como usuario la direcci\u00f3n de Gmail y como contrase\u00f1a la credencial de aplicaci\u00f3n generada previamente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Postfix_Brevo\"><\/span>Postfix + Brevo<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Aqu\u00ed resumo la configuraci\u00f3n final utilizada para <strong>enviar correos<\/strong> desde un servidor propio (Raspberry Pi \/ Debian) usando <strong><a href=\"https:\/\/www.postfix.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Postfix<\/a> como MTA local<\/strong> y <strong><a href=\"https:\/\/app.brevo.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Brevo<\/a> como relay SMTP<\/strong>, evitando los l\u00edmites de Gmail y problemas de entregabilidad.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Como primer paso, es necesario dar de alta el dominio propio en la plataforma de Brevo y autenticarlo correctamente. Este proceso consiste en a\u00f1adir el dominio (por ejemplo, <em>midominio.com<\/em>) desde el panel de Brevo y copiar en el proveedor DNS los registros facilitados por la plataforma. Dichos registros incluyen un c\u00f3digo de verificaci\u00f3n en formato <strong>TXT<\/strong>, dos registros <strong>CNAME<\/strong> para la firma <strong>DKIM<\/strong> y, de forma recomendable, un registro <strong>DMARC<\/strong> que permita mejorar la entregabilidad y el control de los env\u00edos. Una vez a\u00f1adidos y propagados los registros, Brevo debe mostrar el dominio como autenticado, garantizando que los correos enviados desde \u00e9l ser\u00e1n aceptados por los principales proveedores de correo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Una vez autenticado el dominio, es imprescindible definir un remitente v\u00e1lido asociado al mismo. Para ello, se debe crear en Brevo una direcci\u00f3n de env\u00edo del tipo <em><a>noreply@midominio.com<\/a><\/em> y establecerla como remitente predeterminado. Es importante no utilizar direcciones de correo de dominios gratuitos como Gmail, Outlook o Yahoo, ya que estos proveedores bloquean o penalizan los mensajes enviados desde servicios externos que simulan ser remitentes gratuitos. Al utilizar un remitente propio y un dominio previamente autenticado mediante SPF, DKIM y DMARC, se garantiza una mayor fiabilidad en la entrega de los correos y se evita que los mensajes sean descartados o enviados a la carpeta de spam.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 1. Instalaci\u00f3n de Postfix\nsudo apt update\nsudo apt install postfix libsasl2-modules ca-certificates mailutils\n\n# Durante la instalaci\u00f3n cuando nos pregunte Tipo = Internet Site y Nombre del sistema de correo: midominio.com\n\n# 2. Configuraci\u00f3n de Postfix\n#    (Recuerda: en nano copia el script y CTRL+O y enter para guardar y CTRL+X para salir)\nsudo nano \/etc\/postfix\/main.cf<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Identidad\nmyhostname = mail.midominio.com\nmyorigin = \/etc\/mailname\nmydestination = localhost\n\n# Relay SMTP (Brevo)\nrelayhost = [smtp-relay.brevo.com]:587\n\n# TLS\nsmtp_use_tls = yes\nsmtp_tls_security_level = encrypt\nsmtp_tls_CAfile = \/etc\/ssl\/certs\/ca-certificates.crt\n\n# Autenticaci\u00f3n SMTP\nsmtp_sasl_auth_enable = yes\nsmtp_sasl_password_maps = hash:\/etc\/postfix\/sasl_passwd\nsmtp_sasl_security_options = noanonymous\nsmtp_sasl_tls_security_options = noanonymous\nsmtp_sasl_mechanism_filter = plain, login\n\n# Control de ritmo (foros)\ndefault_destination_rate_delay = 2s\nsmtp_destination_concurrency_limit = 5\nsmtp_destination_recipient_limit = 50\n<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 3. Credenciales SMTP (Brevo)\n## En Brevo \u2192 SMTP y API \u2192 SMTP:\n## Usuario SMTP: XXXXXXXX@smtp-brevo.com\n## Generar Clave SMTP (no la API REST)\n\n#    (Recuerda: en nano copia el script y CTRL+O y enter para guardar y CTRL+X para salir)\nsudo nano \/etc\/postfix\/sasl_passwd<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[smtp-relay.brevo.com]:587 XXXXXX@smtp-brevo.com:CLAVE_SMTP_REAL<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 4. Aplicar cambios\nsudo chmod 600 \/etc\/postfix\/sasl_passwd\nsudo postmap \/etc\/postfix\/sasl_passwd\nsudo systemctl restart postfix\n\n# 5. Forzar el remitente correcto\n#    (Recuerda: en nano copia el script y CTRL+O y enter para guardar y CTRL+X para salir)\nsudo nano \/etc\/postfix\/sender_canonical<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/.*\/ noreply@midominio.com<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"md\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># 6. Activar configuraci\u00f3n\nsudo postmap \/etc\/postfix\/sender_canonical || true\nsudo systemctl restart postfix\n\n# 7. Prueba desde consola\necho \"Correo de prueba\" | mail -s \"Test SMTP Brevo\" tuemail@gmail.com\nmailq\n\n# Resultado esperado: Mail queue is empty<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Esta configuraci\u00f3n no est\u00e1 ligada a una aplicaci\u00f3n concreta, sino al propio sistema de env\u00edo de correo del servidor, por lo que resulta igualmente v\u00e1lida para WordPress, otros foros o cualquier aplicaci\u00f3n web que genere correos mediante los mecanismos est\u00e1ndar del sistema. Al utilizar Postfix como gestor de correo local, todas las aplicaciones que recurren a <code>mail()<\/code> o a <code>sendmail<\/code> delegan el env\u00edo real en un \u00fanico punto, que a su vez reenv\u00eda los mensajes a trav\u00e9s de Brevo. Esto permite centralizar el correo saliente, evitar configuraciones SMTP duplicadas en cada aplicaci\u00f3n y aplicar de forma coherente las pol\u00edticas de seguridad, control de ritmo y entregabilidad. Como consecuencia, el servidor puede albergar m\u00faltiples servicios web con un comportamiento estable y predecible en el env\u00edo de correos, convirtiendo esta soluci\u00f3n en una infraestructura gen\u00e9rica, robusta y perfectamente v\u00e1lida para entornos de producci\u00f3n dom\u00e9sticos o semi-profesionales.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Intro Voy a omitir la instalaci&oacute;n de Raspberry PI OS en la microSD. Dispon&eacute;is de cientos de videos y art&iacute;culos al respecto y es por ello que me voy a centrar en los paquetes de software y comandos que considero m&aacute;s importantes. Requisitos Configuraci&oacute;n de DuckDNS en la Raspberry Pi Instalaci&oacute;n de software base Archivos y rutas relevantes Ruta Descripci&oacute;n \/var\/www\/midominio.com\/html\/ Web ra&iacute;z del dominio \/etc\/nginx\/sites-available\/midominio.com VirtualHost nginx \/etc\/nginx\/sites-enabled\/midominio.com Enlace activo \/var\/log\/nginx\/midominio.com.access.log Log de accesos \/var\/log\/nginx\/midominio.com.error.log Log de errores \/etc\/letsencrypt\/&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/garikoitz.info\/blog\/2025\/12\/de-un-vps-comercial-al-salon-de-casa-parte-3-configuracion-basica\/\"> Leer m\u00e1s<span class=\"screen-reader-text\">  Leer m\u00e1s<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":2575,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","wpupg_custom_link":[],"wpupg_custom_link_behaviour":[],"wpupg_custom_link_nofollow":[],"wpupg_custom_image":[],"wpupg_custom_image_id":[],"footnotes":""},"categories":[55,68],"tags":[257,260,253,264,261,262,242,255,252,244,204,254,200,69,256,258,263,259],"class_list":["post-2542","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-raspberry-pi","tag-brevo","tag-cname","tag-configuracion","tag-ddns","tag-dkim","tag-dmark","tag-duckdns","tag-mail","tag-mariadb","tag-nginx","tag-php","tag-postfix","tag-python","tag-raspberry-pi","tag-sendmail","tag-smtp","tag-spf","tag-txt"],"_links":{"self":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/2542","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/comments?post=2542"}],"version-history":[{"count":12,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/2542\/revisions"}],"predecessor-version":[{"id":2590,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/2542\/revisions\/2590"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media\/2575"}],"wp:attachment":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media?parent=2542"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/categories?post=2542"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/tags?post=2542"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}