Marzban en un VPS: panel multiprotocolo Xray con suscripciones
TL;DR
Marzban es un panel de gestión Xray self-hosted que permite crear usuarios, emitir suscripciones y gestionar varios protocolos proxy mediante una interfaz web. En esta guía desplegarás Marzban en Ubuntu Server 24.04 LTS, protegerás el servidor con reglas básicas de seguridad, conectarás HTTPS mediante Caddy, crearás el primer administrador y configurarás copias de seguridad.
- Para un equipo pequeño o uso personal, basta con un VPS de 1–2 vCPU, 2 GB de RAM y 20 GB de SSD.
- Marzban se ejecuta en Docker y utiliza Xray como motor de transporte.
- El panel estará disponible solo mediante HTTPS en un subdominio independiente, por ejemplo
panel.example.com. - Los usuarios reciben un único enlace de suscripción que pueden importar en un cliente compatible.
- Datos clave para la copia de seguridad: SQLite/PostgreSQL, el directorio de Marzban, el archivo de entorno y la configuración de Caddy.
- Para un servidor público, es importante proteger SSH, restringir el acceso al panel y actualizar periódicamente las imágenes Docker.
Qué configuramos y por qué
Marzban es un panel administrativo para Xray. Xray se encarga del funcionamiento de las conexiones de red entrantes, el enrutamiento del tráfico, la gestión de usuarios y los protocolos compatibles. Marzban añade una capa de gestión práctica: interfaz web, API, usuarios, límites de tráfico, fechas de expiración, suscripciones, varios nodos y estadísticas.
El escenario práctico es el siguiente: dispones de un VPS con una dirección IP pública y un dominio. Instalas Marzban, conectas un certificado TLS, creas configuraciones inbound de Xray y añades usuarios. Después, el usuario recibe un enlace de suscripción personal. Lo inserta en una aplicación cliente compatible, y la aplicación obtiene automáticamente la lista de conexiones y la actualiza cuando hay cambios.
El panel es especialmente práctico si necesitas dar servicio no a una sola conexión manual, sino a varios dispositivos o usuarios. En lugar de generar archivos JSON y enlaces individuales manualmente, defines en el panel el nombre de usuario, la duración del acceso, el límite de tráfico y el número de dispositivos. Si es necesario, puedes detener el acceso con un botón o mediante la API.
Qué funcionará tras la configuración
- Panel web de administrador en
https://panel.example.com. - Certificado TLS automático de Let’s Encrypt mediante Caddy.
- Configuración Xray integrada o definida manualmente con varias conexiones inbound.
- Usuarios con UUID, límites de tráfico, fecha de expiración y enlaces de suscripción personales.
- Protección básica del host: claves SSH, UFW, Fail2ban e inicio de sesión root por SSH desactivado.
- Archivo automático de la configuración y la base de datos en almacenamiento S3 externo u otro servidor.
Qué protocolos se pueden utilizar
Marzban no te limita a un único método de conexión: el conjunto viene determinado por la configuración de Xray. Normalmente se despliegan en el servidor varios perfiles inbound para distintos clientes y condiciones de red. En la práctica, suelen utilizarse VLESS con transportes TLS, Trojan con TLS y Shadowsocks. La elección específica debe cumplir tu legislación, las normas del centro de datos y los requisitos de la red donde funcionarán los clientes.
| Tecnología | Función | Cuándo se necesita |
|---|---|---|
| Marzban | Panel, API, usuarios, suscripciones | Cuando se necesita una gestión centralizada de accesos |
| Xray | Núcleo de red y procesamiento de conexiones | Siempre: Marzban gestiona su configuración |
| Caddy | HTTPS reverse proxy para el panel web | Para no publicar el panel por HTTP ni gestionar certificados manualmente |
| Docker Compose | Ejecución y actualización de contenedores | Para un despliegue reproducible y el aislamiento de servicios |
Self-hosted o servicio gestionado
En un servicio gestionado en la nube no necesitas mantener el servidor, actualizar el sistema ni configurar copias de seguridad. Las desventajas son un menor control sobre los datos, la configuración de red, el dominio, los protocolos disponibles y los registros. Además, las condiciones de funcionamiento del servicio pueden cambiar sin tu participación.
Un Marzban self-hosted en un VPS requiere varias horas de configuración inicial, pero proporciona control sobre la infraestructura. Tú eliges la región, la dirección IP, la configuración de Xray, las reglas del firewall, el método de copia de seguridad y la política de acceso de los administradores. Para el propietario de un VPS, suele ser el equilibrio óptimo entre flexibilidad y esfuerzo operativo.
No utilices el panel como un «proxy abierto». Crea cuentas personales, activa límites de tráfico y elimina periódicamente a los usuarios no utilizados. Esto reduce el riesgo de abusos, compromisos y bloqueo de la dirección IP.
Qué configuración de VPS se necesita para esta tarea
Marzban por sí solo apenas carga el procesador. La carga principal la genera Xray: cifrado, número de conexiones simultáneas, volumen de tráfico transmitido y transportes seleccionados. Para uso personal y un equipo pequeño, una red estable y un buen límite mensual de tráfico son más importantes que un gran número de núcleos.
| Escenario | CPU | RAM | Disco | Red |
|---|---|---|---|---|
| 1–10 usuarios, dispositivos personales | 1 vCPU | 2 GB | 20 GB NVMe/SSD | 100 Mbit/s, desde 1 TB de tráfico |
| 10–50 usuarios | 2 vCPU | 4 GB | 40 GB NVMe/SSD | 1 Gbit/s, desde 3–5 TB de tráfico |
| 50–150 usuarios activos | 4 vCPU | 8 GB | 80 GB NVMe/SSD | 1 Gbit/s, límite alto o ilimitado |
| Varios nodos y alta carga | 8+ núcleos dedicados | 16+ GB | 160+ GB NVMe | 1–10 Gbit/s, protección contra DDoS |
Una opción inicial práctica es 2 vCPU, 4 GB de RAM, 40 GB NVMe y un puerto de 1 Gbit/s. Deja margen para Docker, Caddy, registros, actualizaciones y varias decenas de usuarios no demasiado activos. Puedes elegir un VPS con las características indicadas, pero al seleccionar cualquier plan, comprueba de antemano el límite mensual de tráfico, la disponibilidad de IPv4, las reglas para servicios de red y la región de alojamiento.
Cuándo es suficiente un VPS
Un VPS es adecuado para casi todos los escenarios iniciales: infraestructura personal, un equipo pequeño, pruebas de configuraciones y hasta varias decenas de usuarios activos regularmente. En un servidor virtual es más fácil cambiar de plan, reinstalar rápidamente el sistema operativo, crear una instantánea y trasladar el servicio a otra región.
Cuándo se necesita un dedicated
Un servidor dedicado se justifica si el procesador está constantemente cargado por el cifrado, atiendes a cientos de clientes activos, ejecutas varios nodos en una misma máquina o es fundamental la previsibilidad del rendimiento. Un dedicated también es útil cuando se necesita mucho espacio en disco, un puerto de red superior a 1 Gbit/s o requisitos especiales para filtros de red. No migres a él solo por el número de usuarios registrados: guíate por las conexiones simultáneas, la velocidad y las métricas reales de CPU/RAM.
Cómo afecta la ubicación del servidor
La ubicación afecta a la latencia, la velocidad hacia los recursos de destino, la disponibilidad de direcciones IP y el coste del tráfico. Si los usuarios están en una misma región, elige un centro de datos con la menor latencia posible hacia ellos. Para comprobarlo antes de comprar, puedes comparar looking glass públicos, IP de prueba o rutas mediante mtr.
No elijas la ubicación solo por la geografía. A veces, un servidor en un país vecino tiene un peering más favorable y una velocidad real notablemente mejor. Tras el lanzamiento, mide la latencia desde varias redes de clientes, no solo desde el Wi-Fi doméstico.
Preparación del servidor
A continuación se utiliza Ubuntu Server 24.04 LTS x86_64. A comienzos de 2026, esta es una rama LTS estable con soporte a largo plazo y paquetes Docker actualizados. Comience con un servidor limpio que tenga una dirección IPv4 pública y un registro DNS de tipo A para el dominio del panel.
Antes de instalar Marzban, cree los registros DNS. Como mínimo se necesitan panel.example.com para el panel de administración y, opcionalmente, sub.example.com para la entrega de suscripciones. En la primera etapa puede utilizar un solo dominio para ambos fines. El registro debe apuntar a la IPv4 del servidor, y el proxy del proveedor DNS debe desactivarse si interfiere con la emisión del certificado TLS o el funcionamiento del transporte seleccionado.
Conexión y actualización del sistema
Inicie sesión en el servidor como el usuario root proporcionado por el proveedor y actualice inmediatamente el sistema base. Solo es necesario reiniciar si se actualizó el kernel o si el sistema indica explícitamente que se requiere un reinicio.
apt update && apt full-upgrade -y
apt autoremove --purge -y
reboot
Después del reinicio, vuelva a conectarse. A continuación, cree un usuario administrador independiente. El ejemplo utiliza el nombre deploy; sustitúyalo por el suyo.
adduser deploy
usermod -aG sudo deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
Copie la clave pública SSH desde el equipo local. Ejecute el comando localmente, no en el VPS. Tras comprobar correctamente el nuevo acceso, no cierre la sesión root actual hasta confirmar que la clave funciona.
ssh-copy-id deploy@SERVER_IP
ssh deploy@SERVER_IP
Protección de SSH
Abra la configuración de SSH y desactive el acceso directo de root, la autenticación por contraseña y las contraseñas vacías. Primero asegúrese de que el usuario deploy realmente tenga una clave funcional.
sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
AllowUsers deploy
Compruebe la sintaxis y aplique la configuración. Si el comando sshd -t no muestra ninguna salida, la configuración es correcta.
sudo sshd -t && sudo systemctl restart ssh
sudo systemctl status ssh --no-pager
Utilidades básicas, UFW y Fail2ban
Instale herramientas de diagnóstico, el firewall y protección contra intentos de fuerza bruta en contraseñas SSH. Incluso con la autenticación por contraseña desactivada, Fail2ban resulta útil como nivel adicional de protección y para futuros servicios.
sudo apt install -y ca-certificates curl gnupg lsb-release \
ufw fail2ban jq unzip nano htop tmux \
dnsutils mtr-tiny chrony
Abra únicamente SSH, HTTP y HTTPS. No es necesario abrir al exterior el puerto 8000 del panel Marzban: Caddy accederá a él localmente. Los puertos de entrada de Xray se añaden por separado después de definir la configuración.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Compruebe la sincronización de hora. Un reloj incorrecto rompe TLS, los tokens y el diagnóstico de conexiones.
sudo systemctl enable --now chrony
timedatectl status
sudo fail2ban-client status sshd
Si administra el servidor mediante un puerto SSH no estándar, primero añada una regla UFW para el nuevo puerto y compruebe la nueva conexión. Solo entonces elimine la regla para el puerto estándar 22.
Instalación del software — paso a paso
Marzban se distribuye como una imagen Docker, y el script oficial de instalación crea un directorio, descarga la configuración de Compose e inicia el servicio. Para 2026, se recomienda Docker Engine 27 o posterior y Docker Compose Plugin v2. En un entorno de producción, no dependa de la etiqueta no verificable latest: después de un inicio exitoso, fije una imagen específica probada en su máquina.
Paso 1. Instalación de Docker Engine desde el repositorio oficial
Elimine los paquetes Docker antiguos que puedan generar conflictos, si están presentes. Esto evita conflictos entre los paquetes de Ubuntu y el Docker Engine oficial.
sudo apt remove -y docker.io docker-compose docker-compose-v2 \
docker-doc podman-docker containerd runc 2>/dev/null || true
Añada la clave y el repositorio de Docker para Ubuntu 24.04. El comando utiliza automáticamente la arquitectura del sistema y el nombre en clave de la versión actual.
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
Instale Docker Engine, CLI, containerd y el moderno Compose Plugin. Después de instalarlo, habilite el servicio para que los contenedores se inicien tras reiniciar el VPS.
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker version
sudo docker compose version
Añada el usuario deploy al grupo Docker. Después deberá salir de la sesión SSH y volver a conectarse para que se apliquen los grupos. Recuerde: la pertenencia al grupo docker otorga efectivamente privilegios root en el servidor.
sudo usermod -aG docker deploy
exit
Paso 2. Instalación de Marzban
Vuelva a conectarse como el usuario deploy. El script oficial de instalación de Marzban crea el directorio de trabajo /opt/marzban, descarga Docker Compose y prepara el servicio. Antes de ejecutarlo, conviene revisar el script descargado en el navegador o mediante curl, especialmente en un servidor de producción.
ssh deploy@SERVER_IP
curl -fsSL https://github.com/Gozargah/Marzban-scripts/raw/master/marzban.sh \
-o /tmp/marzban.sh
less /tmp/marzban.sh
Si el contenido corresponde al repositorio oficial del proyecto, ejecute la instalación. El script solicitará la contraseña sudo del usuario y descargará los contenedores necesarios.
bash /tmp/marzban.sh install
Después de la instalación, compruebe los contenedores. Los nombres pueden variar ligeramente entre versiones, pero el contenedor del panel Marzban debe estar en ejecución y no debe haber errores cíclicos en los registros.
cd /opt/marzban
sudo docker compose ps
sudo docker compose logs --tail=100 marzban
Paso 3. Creación del primer administrador
Marzban no debe tener credenciales de administrador conocidas públicamente. Cree un nombre de usuario y una contraseña largos e independientes mediante la CLI dentro del contenedor. No utilice para el panel la misma contraseña que para el usuario de Linux, el correo electrónico o el registrador del dominio.
cd /opt/marzban
sudo docker compose exec marzban marzban cli admin create \
--sudo
El comando solicitará de forma interactiva el nombre de usuario y la contraseña. Puede generar una contraseña segura localmente o en el servidor.
openssl rand -base64 32
Paso 4. Comprobación de la interfaz local
Antes de conectar Caddy, asegúrese de que la aplicación escucha en un puerto local. En una instalación típica, Marzban utiliza el puerto 8000. Si el comando no muestra un puerto en escucha o el contenedor se reinicia constantemente, vaya a la sección de troubleshooting en lugar de publicar el panel en Internet.
sudo ss -ltnp | grep 8000
curl -I http://127.0.0.1:8000
La respuesta puede ser 200, 302, 401 o 404, según la versión de la interfaz y la ruta. Lo importante es recibir una respuesta HTTP del proceso local, no un error de conexión.
Configuración de Marzban, Xray y HTTPS
En esta sección, el panel permanece disponible solo localmente en 127.0.0.1:8000, y Caddy recibe el HTTPS externo. Este esquema no requiere abrir el puerto de Marzban al exterior, simplifica la emisión del certificado y permite configurar centralizadamente las cabeceras HTTP.
Comprobación de archivos de Marzban
Después de la instalación, compruebe el contenido del directorio. Por lo general, aquí se encuentran docker-compose.yml, .env, el directorio de datos y la plantilla de configuración de Xray. No publique el archivo .env en Git, notas en la nube o mensajeros: puede contener credenciales y la dirección de la base de datos.
cd /opt/marzban
sudo ls -la
sudo find . -maxdepth 2 -type f | sort
sudo chmod 600 .env
Abra el archivo de entorno y compruebe los parámetros clave. Los nombres de las variables pueden diferir ligeramente según la versión concreta de Marzban, así que no elimine las líneas generadas automáticamente. A continuación se muestra una referencia para la base de datos SQLite integrada y el servidor Uvicorn local.
sudo nano /opt/marzban/.env
# El panel está disponible solo para el reverse proxy local
UVICORN_HOST=127.0.0.1
UVICORN_PORT=8000
# La base de datos SQLite local es adecuada para un solo servidor
SQLALCHEMY_DATABASE_URL=sqlite:////var/lib/marzban/db.sqlite3
# Ruta a la configuración de Xray dentro del contenedor
XRAY_JSON=/var/lib/marzban/xray_config.json
# No almacene contraseñas ni tokens en un repositorio público
# SUDO_USERNAME y SUDO_PASSWORD se configuran mediante CLI o variables de entorno
Si el archivo Compose de instalación publica 8000:8000 en todas las interfaces, cambie la publicación del puerto a localhost. Antes de editar, haga una copia del archivo. En algunas versiones de Marzban se utiliza el modo host network; en ese caso, la restricción se realiza mediante UVICORN_HOST=127.0.0.1.
cd /opt/marzban
sudo cp docker-compose.yml docker-compose.yml.bak
sudo nano docker-compose.yml
services:
marzban:
ports:
- "127.0.0.1:8000:8000"
No inserte este fragmento sobre todo el archivo: muestra únicamente la sección necesaria. Conserve los demás volumes, environment, restart policy y ajustes de imagen creados por el instalador. Después del cambio, compruebe el YAML y reinicie la pila.
cd /opt/marzban
sudo docker compose config > /dev/null
sudo docker compose up -d
sudo docker compose ps
curl -I http://127.0.0.1:8000
Instalación de Caddy
Caddy obtiene y renueva automáticamente certificados Let’s Encrypt si el dominio apunta al servidor y los puertos 80 y 443 están accesibles desde el exterior. Instale Caddy desde el repositorio oficial. Antes de hacerlo, asegúrese de que otro servidor web no esté ocupando el puerto 80 o 443.
sudo apt install -y debian-keyring debian-archive-keyring \
apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy
Cree el Caddyfile. Sustituya el dominio, la dirección de correo electrónico para las notificaciones de Let’s Encrypt y, si es necesario, la lista de direcciones IP permitidas. La restricción por IP es una protección útil para el panel si tiene una IP doméstica estática o una salida VPN.
sudo nano /etc/caddy/Caddyfile
{
email [email protected]
}
panel.example.com {
encode zstd gzip
@admin {
path /dashboard /api/admin /docs /openapi.json
}
reverse_proxy 127.0.0.1:8000
header {
-Server
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
}
log {
output file /var/log/caddy/marzban-access.log
format json
}
}
El bloque @admin en este ejemplo mínimo no se aplica por separado: se deja como plantilla para una futura restricción por IP. No añada una autorización Caddy sin considerarlo bien sobre el panel hasta comprobar que no interfiera con la API y las rutas de subscription.
Compruebe la configuración y recargue Caddy. En el primer inicio solicitará un certificado; normalmente tarda unos segundos.
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo systemctl enable --now caddy
sudo systemctl status caddy --no-pager
Compruebe HTTPS desde el propio VPS y desde el equipo local. Se espera una respuesta sin errores de certificado. Si el certificado no se emite, compruebe primero el DNS, los puertos abiertos y los registros de Caddy.
curl -I https://panel.example.com
sudo journalctl -u caddy -n 100 --no-pager
sudo ufw status numbered
Configuración del inbound en el panel
Abra https://panel.example.com, inicie sesión con el administrador creado y vaya a la sección de gestión de la configuración host/inbound. La interfaz cambia entre versiones, pero la lógica es la misma: Marzban almacena la plantilla JSON de Xray, inicia Xray e inserta usuarios en los objetos inbound correspondientes.
Para el primer inicio, cree un inbound claro, pruébelo en un dispositivo y solo después añada otros adicionales. No mezcle una decena de transportes en la primera configuración: si hay un error, será difícil entender dónde está exactamente el problema: DNS, TLS, puerto, JSON o cliente.
El ejemplo simplificado de Xray JSON a continuación muestra la estructura de un inbound VLESS. Marzban normalmente inserta automáticamente los valores UUID de usuario, por lo que la lista de clientes se deja con una variable de plantilla compatible con su versión del panel. Utilice el JSON generado por la interfaz de Marzban como fuente principal de referencia.
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "vless-main",
"listen": "0.0.0.0",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"certificateFile": "/var/lib/marzban/certs/fullchain.pem",
"keyFile": "/var/lib/marzban/certs/privkey.pem"
}
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
}
]
}
Este ejemplo no es una plantilla universal de producción: los archivos TLS, los clientes de plantilla, el transport y el puerto deben estar coordinados con su esquema concreto. Si Caddy ya ocupa 443/tcp, Xray no puede escuchar simultáneamente en la misma IP y puerto de esta forma. Utilice un puerto independiente para Xray o diseñe una entrada compartida teniendo en cuenta el transporte seleccionado y la documentación de Marzban/Xray.
Usuario, suscripción y comprobación
En el panel, cree un usuario de prueba con una duración corta, por ejemplo 24 horas, un límite de 1 GB y un dispositivo. Después de crearlo, copie la URL de subscription de la tarjeta del usuario. Una ruta típica tiene el aspecto de https://panel.example.com/sub/ТОКЕН, pero la ruta exacta depende de la configuración y la versión de Marzban.
Abra el enlace en el navegador o compruébelo mediante curl. No publique esta URL en capturas de pantalla ni tickets: el token proporciona acceso a la configuración del usuario.
curl -fsS "https://panel.example.com/sub/USER_SUBSCRIPTION_TOKEN" | head
sudo docker compose -f /opt/marzban/docker-compose.yml logs --tail=100 marzban
sudo docker stats --no-stream
Importe la URL de subscription en un cliente compatible con el formato que utiliza. Luego conéctese y compruebe que la dirección IP externa cambia a la IP del servidor y que el contador de tráfico aumenta en el panel. Para el diagnóstico en el VPS, utilice los registros de Marzban, los registros de Xray y la lista de puertos en escucha.
curl -4 https://ifconfig.me/ip ; echo
sudo ss -lntup
sudo docker compose -f /opt/marzban/docker-compose.yml logs --tail=200
Copias de seguridad y mantenimiento
Una copia de seguridad de Marzban no es necesaria para restaurar imágenes de Docker, sino para restaurar el estado: la base de datos de usuarios, límites, tokens, configuración de Xray, variables de entorno y ajustes TLS del reverse proxy. Si solo se pierde el contenedor, se vuelve a crear. Si se pierde la base de datos, habrá que crear de nuevo los usuarios y emitir nuevos enlaces de subscription.
Qué incluir en la copia de seguridad
/opt/marzban— archivos Compose,.env, datos y plantillas de Xray.- El archivo de base de datos SQLite, si se utiliza SQLite; normalmente se encuentra dentro del directorio de datos de Marzban.
- Un volcado de PostgreSQL, si trasladó la base de datos a un contenedor o servidor independiente.
/etc/caddy/Caddyfile— configuración del reverse proxy HTTPS./var/lib/caddy— certificados y estado de Caddy, si desea una restauración rápida.- La lista de puertos abiertos y las instrucciones de restauración, guardadas por separado del servidor.
No guarde la única copia en el mismo VPS. La eliminación de la máquina virtual, un fallo de disco, el compromiso de la cuenta root o un comando rm erróneo destruirán tanto el servicio como el archivo local. Un buen esquema consiste en una copia de seguridad restic cifrada en almacenamiento compatible con S3, Backblaze B2 o un VPS independiente mediante SFTP.
Instalación de restic y preparación del repositorio
A continuación se muestra un ejemplo con almacenamiento compatible con S3. No introduzca los valores de las claves en el historial de shell sin necesidad. Es mejor guardarlos en un archivo con permisos 600.
sudo apt install -y restic
sudo install -d -m 700 /root/.config/restic
sudo nano /root/.config/restic/marzban.env
sudo chmod 600 /root/.config/restic/marzban.env
export RESTIC_REPOSITORY="s3:https://s3.example.net/marzban-backups"
export RESTIC_PASSWORD="CHANGE_TO_A_LONG_UNIQUE_BACKUP_PASSWORD"
export AWS_ACCESS_KEY_ID="S3_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="S3_SECRET_KEY"
Inicialice un repositorio vacío una sola vez. Si el comando finaliza correctamente, restic creará una estructura de servicio en el bucket especificado.
sudo bash -c 'source /root/.config/restic/marzban.env && restic init'
Script de copia de seguridad
Antes de copiar SQLite, es recomendable detener brevemente el contenedor o crear una copia coherente de la base de datos. Para un servidor pequeño, es más seguro realizar una breve pausa de Marzban: los usuarios con conexiones ya iniciadas podrían perder temporalmente la posibilidad de cambiar la suscripción, pero la copia de seguridad será íntegra. Si utiliza PostgreSQL, use pg_dump en lugar de copiar los archivos de la base de datos.
sudo nano /usr/local/sbin/backup-marzban.sh
sudo chmod 700 /usr/local/sbin/backup-marzban.sh
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/marzban"
STAMP="$(date +%F-%H%M%S)"
mkdir -p "$BACKUP_DIR"
cd /opt/marzban
docker compose stop marzban
tar --xattrs --acls -czf "$BACKUP_DIR/marzban-$STAMP.tar.gz" \
/opt/marzban \
/etc/caddy/Caddyfile \
/var/lib/caddy 2>/dev/null || true
docker compose start marzban
source /root/.config/restic/marzban.env
restic backup "$BACKUP_DIR" --tag marzban --tag "$(hostname)"
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
find "$BACKUP_DIR" -type f -mtime +2 -delete
Pruebe el script manualmente antes de automatizarlo. Tras su ejecución, debe aparecer un snapshot en restic y el contenedor Marzban debe volver a estar en estado Up.
sudo /usr/local/sbin/backup-marzban.sh
sudo bash -c 'source /root/.config/restic/marzban.env && restic snapshots'
sudo docker compose -f /opt/marzban/docker-compose.yml ps
Ejecución automática mediante cron
Ejecute la copia de seguridad cada noche. Cron es adecuado para una tarea individual sencilla; si hay muchos servidores, es más conveniente pasar a systemd timer, Ansible o un sistema centralizado de copias de seguridad.
sudo crontab -e
25 3 /usr/local/sbin/backup-marzban.sh >> /var/log/backup-marzban.log 2>&1
Al menos una vez por trimestre, realice una restauración de prueba en una máquina temporal independiente. Una copia de seguridad cuya restauración nunca se ha comprobado no puede considerarse funcional. Para ver el contenido del archivo, use restic restore en un directorio de prueba, sin sobrescribir los archivos de producción.
Actualizaciones de Marzban y del sistema
Para un solo VPS, actualice Marzban durante una ventana de mantenimiento: avise a los usuarios, realice una copia de seguridad, descargue la imagen, reinicie el contenedor y revise los logs. Es más seguro que actualizar a ciegas durante la noche mediante cron. La aplicación automática de security-updates para Ubuntu es aceptable, pero es mejor controlar manualmente las actualizaciones major de Docker, Marzban y Xray.
cd /opt/marzban
sudo /usr/local/sbin/backup-marzban.sh
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune -f
sudo docker compose logs --tail=100 marzban
Con varios nodos, aplique una actualización rolling: primero actualice el nodo menos cargado, compruebe las conexiones y las métricas, y después actualice los demás. No actualice simultáneamente el panel, todos los nodos Xray, el sistema operativo y el esquema de la base de datos: si surge un problema, será imposible determinar rápidamente la causa.
Solución de problemas y FAQ
¿Por qué el panel no se abre por HTTPS y Caddy muestra un error al obtener el certificado?
Primero compruebe el DNS: dig +short panel.example.com A debe devolver la IP de su VPS. A continuación, asegúrese de que los puertos 80 y 443 estén abiertos en UFW y en el firewall de red del proveedor. Compruebe si hay otro servidor web en ejecución: sudo ss -ltnp | grep -E ':80|:443'. En los logs de journalctl -u caddy suele indicarse directamente la causa: DNS incorrecto, puerto cerrado, rate limit o conflicto de servicios.
¿Por qué Caddy devuelve 502 Bad Gateway?
El error 502 significa que Caddy funciona, pero no puede conectarse a Marzban. Compruebe el contenedor: sudo docker compose -f /opt/marzban/docker-compose.yml ps. A continuación, ejecute curl -I http://127.0.0.1:8000 en el propio VPS. Si no hay respuesta, revise los logs del contenedor y compruebe el valor de UVICORN_HOST/UVICORN_PORT en .env. Después de realizar cambios, aplique docker compose up -d y reinicie Caddy.
¿Por qué el contenedor Marzban se reinicia constantemente?
Ejecute sudo docker compose logs --tail=200 marzban. Las causas frecuentes son: un error de sintaxis en .env, YAML Compose dañado, un archivo Xray JSON inaccesible, conflicto de puertos o falta de espacio en disco. Compruebe el espacio libre con df -h y la memoria con free -h. Antes de modificar la configuración, restaure una copia de seguridad del archivo, por ejemplo docker-compose.yml.bak, y luego ejecute docker compose config para verificarla.
El usuario importó una subscription URL, pero las conexiones no funcionan. ¿Qué se debe comprobar?
Compruebe por separado tres niveles: la subscription URL, el inbound de Xray y el cliente. Primero abra el enlace mediante curl: debe devolver configuraciones, no una página HTML de error. Luego asegúrese de que el puerto inbound necesario está escuchando mediante ss -lntup y permitido en UFW. Por último, compruebe el dominio, SNI, UUID, el certificado TLS y la hora del sistema del cliente. Comience con un inbound sencillo y un usuario de prueba.
¿Por qué no se contabiliza el tráfico del usuario o el límite no deshabilita el acceso?
Primero compruebe que el usuario se conecta precisamente a través del inbound gestionado por Marzban, y no mediante un proceso Xray antiguo iniciado manualmente. Revise los logs y las estadísticas en el panel después de una nueva conexión. El error suele producirse si el JSON de Xray se editó manualmente y perdió la plantilla de clientes de Marzban. No modifique la estructura de los objetos de usuario sin comprender las plantillas del panel. Tras cambiar la configuración, cree un nuevo usuario de prueba y compruébelo por separado.
¿Qué configuración mínima de VPS es adecuada?
El mínimo para uso personal es 1 vCPU, 2 GB de RAM, 20 GB de SSD/NVMe, IPv4 pública y un puerto de 100 Mbit/s o superior. Este servidor es adecuado para varios dispositivos y entre 1 y 10 usuarios no demasiado activos. Para una operación más cómoda, es mejor empezar con 2 vCPU y 4 GB de RAM: habrá margen para Docker, logs, Caddy, actualizaciones y picos de carga breves. Lo más importante es comprobar el límite de tráfico y la calidad de la red.
¿Qué elegir: VPS o dedicated para esta tarea?
Para la mayoría de las instalaciones de Marzban, elija un VPS: es más económico, se despliega más rápido, se escala fácilmente según el plan y es adecuado para hasta decenas de usuarios activos. Dedicated es necesario con una carga alta y estable de CPU, cientos de clientes simultáneos, varios nodos en un mismo servidor, requisitos de gran capacidad de disco o un puerto superior a 1 Gbit/s. Tome la decisión según las métricas: si la CPU se mantiene por encima del 70 %, aumenta la latency y aparecen pérdidas de velocidad, es hora de considerar un servidor dedicado o el escalado horizontal.
¿Se puede abrir el panel directamente en el puerto 8000?
Técnicamente es posible, pero es una mala práctica para production. El acceso HTTP directo transmite la contraseña del administrador sin protección, y el puerto abierto facilita el escaneo y los ataques. Mantenga Marzban en 127.0.0.1:8000 y publique externamente solo Caddy mediante HTTPS en el puerto 443. Si necesita acceso temporal para diagnóstico, utilice un túnel SSH: ssh -L 8000:127.0.0.1:8000 deploy@SERVER_IP, y después abra la dirección local en el navegador.
¿Cómo restaurar Marzban después de migrarlo a un nuevo VPS?
Instale Docker, Marzban y Caddy en el nuevo servidor, pero no cree usuarios nuevos sobre la base de datos anterior. Copie el archivo desde restic a un directorio temporal, detenga Marzban, restaure /opt/marzban y Caddyfile, establezca los permisos correctos y luego inicie Compose. Después de cambiar la IP, actualice el DNS y espere a que se propague el registro. Compruebe el panel, la subscription URL, el certificado y una conexión de prueba antes de desconectar definitivamente el VPS antiguo.
Conclusiones y próximos pasos
Ahora dispone de Marzban en un VPS con Docker, SSH protegido, panel HTTPS, filtrado básico de red y copias de seguridad automáticas. El panel permite crear centralizadamente usuarios de Xray, emitir suscripciones y controlar fechas de expiración o límites de tráfico.
- Añada uno o dos perfiles inbound adicionales solo después de probar la configuración básica con un cliente real.
- Configure la monitorización de CPU, RAM, disco, disponibilidad de HTTPS y la fecha de la última copia de seguridad correcta.
- Cuando aumente la carga, traslade PostgreSQL y los nodos Xray a servidores independientes, manteniendo Marzban como panel de gestión central.
Revise los logs con regularidad, pruebe la restauración desde una copia de seguridad y actualice los componentes durante una ventana de mantenimiento planificada. Esto es más importante que una configuración compleja: un servidor estable, documentado y recuperable es más fiable que un conjunto de ajustes no probados.