Implemente MoreLogin en un servidor Ubuntu sin cabeza y automatice los perfiles del navegador a través de la API local, sin necesidad de un entorno de escritorio.
Al final de esta guía tendrás:
- Una instancia de MoreLogin en ejecución en un servidor sin cabeza Ubuntu 24.04
- Reenvío de red configurado para que las máquinas externas puedan conectarse a través de CDP (Protocolo Chrome DevTools)
- Un script de automatización de Python funcional que crea, inicia, controla y limpia perfiles del navegador.
┌──────────────────────────────────────────────────────────┐
│ Ubuntu 24.04 Server │
│ │
│ ┌──────────────┐ ┌───────────────────────────────┐ │
│ │ xvfb │───▶│ MoreLogin AppImage │ │
│ │ (virtual │ │ Local API :40000 │ │
│ │ display) │ │ CDP debug :<dynamic> │ │
│ │ │ │ (127.0.0.1, per profile) │ │
│ └──────────────┘ └───────────────────────────────┘ │
│ │ │
│ socat forwarding │
│ │ │
│ 0.0.0.0:40001 → 127.0.0.1:40000 │
│ 0.0.0.0:<N+1> → 127.0.0.1:<N> │
└──────────────────────────────────────────────────────────┘
│
External machine
(Playwright / Puppeteer / Selenium)[!NOTE] El puerto de depuración de CDP es dinámico: cada perfil de navegador tiene su propio puerto, devuelto por el punto final
/api/env/start. El diagrama anterior utiliza<N>como marcador de posición.
| Requisito | Detalles |
|---|---|
| Sistema operativo | Servidor Ubuntu 24.04 (x86_64) |
| Especificaciones recomendadas | 8 vCPU, 8 GB de RAM (admite ~5 perfiles simultáneos) |
| Red | Acceso a Internet saliente; abra el puerto de entrada 40001 y los puertos CDP reenviados que elija, o utilice túneles SSH en su lugar |
| Python (opcional) | Python 3.8+ con pip para ejecutar el script de ejemplo |
Conéctese a su servidor a través de SSH e instale los paquetes requeridos:
# FUSE support (required for AppImage)
sudo apt install -y libfuse2t64
# GTK / accessibility / display libraries
sudo apt install -y libatk1.0-0 libatk-bridge2.0-0 libatspi2.0-0
sudo apt install -y libcups2
sudo apt install -y libgtk-3-0 libgdk-pixbuf2.0-0
sudo apt install -y libgbm1 libxkbcommon0 libasound2t64
# Virtual framebuffer (headless display)
sudo apt install -y xvfb
# TCP forwarder
sudo apt install -y socatSi las páginas del navegador se muestran sin texto o muestran caracteres faltantes, instale los paquetes de fuentes correspondientes:
# CJK (Chinese, Japanese, Korean)
sudo apt install -y fonts-noto-cjk fonts-noto-cjk-extra
# Arabic
sudo apt install -y fonts-noto-color-emoji fonts-noto-extraPara otros idiomas, instale el paquete familia de fuentes Noto correspondiente.
wget https://get.morelogin.com/client/prod/linux/x64/2.54.0/MoreLogin_x86_64_2.54.0.AppImage
chmod +x MoreLogin_x86_64_2.54.0.AppImageReemplace
2.54.0con la última versión disponible en su cuenta MoreLogin o en la página de descarga.
Utilice xvfb-run para proporcionar una pantalla virtual, luego ejecute AppImage:
nohup xvfb-run -a ./MoreLogin_x86_64_2.54.0.AppImage --no-sandbox > morelogin.log 2>&1 &Verifique que haya comenzado exitosamente:
# Check the process is running
ps aux | grep MoreLoginEl proceso puede tardar entre 5 y 10 segundos en inicializarse por completo.
[!CAUTION] Debe iniciar sesión antes de llamar a cualquier otro punto final de API local. En un servidor sin cabeza no hay una GUI para iniciar sesión manualmente, por lo que debe autenticarse a través de la API. Sin este paso, todas las llamadas API devolverán:
{"status": "error", "code": 401, "message": "Su estado de inicio de sesión ha caducado, inicie sesión nuevamente"}
Abra el cliente de escritorio MoreLogin (en cualquier máquina en la que haya iniciado sesión) y navegue hasta Configuración → API y MCP. Copie el ID de aplicación y la Clave de API de la sección Abrir API:

Llame al punto final de inicio de sesión con sus credenciales:
curl -X POST http://127.0.0.1:40000/api/user/login \
-H "Content-Type: application/json" \
-d '{
"apiId": "YOUR_APP_ID",
"apiKey": "YOUR_API_KEY"
}'Una respuesta exitosa se parece a:
{"code": 0, "msg": null, "data": true}Confirme que la API esté lista enumerando los perfiles del navegador:
curl -s -X POST http://127.0.0.1:40000/api/env/page \
-H "Content-Type: application/json" \
-d '{"pageNo": 1, "pageSize": 1}'Una respuesta
{"code":0, ...}significa que ha iniciado sesión y que la API está lista.
Punto de control: Su servidor MoreLogin está en pleno funcionamiento. Continúe con el Paso 4 para obtener acceso remoto o vaya directamente al Paso 5 si ejecuta scripts en el mismo servidor.
[!NOTE] La sesión de inicio de sesión persiste mientras se esté ejecutando el proceso MoreLogin. Si reinicia AppImage, deberá iniciar sesión nuevamente.
De forma predeterminada, tanto la API local (:40000) como los puertos de depuración del CDP se vinculan a 127.0.0.1. Si necesita acceder a ellos desde una máquina externa (por ejemplo, su computadora portátil de desarrollo), use socat para reenviar el tráfico.
[!WARNING] Riesgo de seguridad: no exponga estos puertos a la Internet pública.
- La API local no tiene autenticación integrada para la mayoría de los puntos finales.
- Un puerto de depuración CDP otorga control remoto total de la instancia del navegador (leer cookies, inyectar scripts, capturar capturas de pantalla).
Recomendaciones:
- Utilice un túnel SSH en lugar de socat para acceso remoto:
ssh -L 40000:127.0.0.1:40000 user@server- Si debe usar socat, restrinja el acceso con reglas de firewall a IP específicas únicamente
- Utilice una VPN o grupos de seguridad de proveedores de nube para limitar el tráfico entrante
- Nunca abra los puertos
40001/CDP a0.0.0.0en un servidor público sin restricciones de IP
nohup socat TCP-LISTEN:40001,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:40000 &Las máquinas externas ahora pueden acceder a la API en
http://<server-ip>:40001.
Cuando inicia un perfil de navegador a través de la API, la respuesta incluye un debugPort dinámico (por ejemplo, 9222). Cada perfil puede recibir un puerto diferente. Reenvíelo para que las herramientas de automatización externas (Playwright, Puppeteer, Selenium) puedan conectarse:
# Example: if debugPort=9222, forward to external port 9223 (debugPort + 1)
# Adjust both ports to match the actual debugPort returned by /api/env/start
nohup socat TCP-LISTEN:9223,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:9222 &[!WARNING] Cuando ejecute varios perfiles simultáneamente, asegúrese de que los puertos reenviados no choquen con los puertos de depuración de otros perfiles. Por ejemplo, si el perfil A obtiene
debugPort=9222y usted reenvía a9223, pero el perfil B recibedebugPort=9223, habrá un conflicto de puerto. Considere utilizar un desplazamiento mayor o un rango de puertos dedicado.
[!TIP] En producción, cree el reenvío socat dinámicamente después de cada llamada
/api/env/start, utilizando eldebugPortdevuelto. Consulte el ejemplo de Python para ver una implementación funcional.
Si ejecuta scripts de automatización en el mismo servidor, puede omitir socat y conectarse directamente a
127.0.0.1.
Si usa socat, restrinja el acceso solo a direcciones IP confiables:
# Allow only a specific IP (recommended)
sudo ufw allow from <YOUR_IP> to any port 40001 proto tcp
sudo ufw allow from <YOUR_IP> to any port 9223 proto tcp
# Or allow from any IP (NOT recommended for production)
# sudo ufw allow 40001/tcp
# sudo ufw allow 9223/tcpPara obtener el acceso remoto más seguro, utilice un túnel SSH: no se necesitan cambios en el firewall ni socat.
Debido a que el puerto CDP es dinámico (asignado cuando inicia un perfil), el flujo de trabajo es:
Primero canalice el puerto API:
# Run this on your local machine ssh -L 40000:127.0.0.1:40000 user@<server-ip>Inicie el perfil a través de la API tunelizada (
http://127.0.0.1:40000/api/env/start) y lea eldebugPortdevuelto.Abrir un segundo túnel para el puerto CDP:
# Replace <debugPort> with the actual port returned by the API ssh -L <debugPort>:127.0.0.1:<debugPort> user@<server-ip>Conéctate a
http://127.0.0.1:<debugPort>desde tus scripts locales de Playwright/Puppeteer como si el servidor fuera local.
[!TIP] Puede combinar ambos túneles en un comando si conoce el rango de puertos de antemano, por ejemplo:
ssh -L 40000:127.0.0.1:40000 -L 9222:127.0.0.1:9222 -L 9223:127.0.0.1:9223 usuario@<ip-servidor>Pero en la práctica es más fácil iniciar primero el túnel API y luego agregar túneles por perfil según sea necesario.
A continuación se muestra un ejemplo mínimo de Python que muestra el ciclo de vida completo de un perfil de navegador. Para obtener el script completo listo para producción con simultaneidad y manejo de errores, consulte el ejemplo completo en GitHub.
pip install requests playwrightPlaywright se utiliza aquí solo para su cliente CDP (
connect_over_cdp). No es necesario ejecutarplaywright install: MoreLogin proporciona su propio navegador.
En Linux Server, el motor del navegador debe ejecutarse con la bandera --no-sandbox. Este parámetro se pasa a través del campo startupParams al crear o actualizar un perfil de navegador.
[!CAUTION] Sin
--no-sandbox, el navegador no podrá iniciarse en la mayoría de los entornos de servidor Linux (especialmente al ejecutar comorooto sin una sesión de escritorio completa).
Use /api/env/create/advanced para crear un perfil con startupParams (el endpoint /api/env/create/quick no soporta este campo):
curl -X POST http://127.0.0.1:40000/api/env/create/advanced \
-H "Content-Type: application/json" \
-d '{
"browserTypeId": 1,
"operatorSystemId": 5,
"startupParams": ["--no-sandbox"]
}'[!TIP] Si usó
/api/env/create/quickpara crear el perfil, llame a/api/env/updatepara agregar--no-sandboxantes de iniciarlo — vea a continuación.
Si ya tiene perfiles de navegador creados sin --no-sandbox, actualícelos antes de iniciar:
curl -X POST http://127.0.0.1:40000/api/env/update \
-H "Content-Type: application/json" \
-d '{
"envId": "YOUR_ENV_ID",
"startupParams": ["--no-sandbox"]
}'[!NOTE] El campo
startupParamsacepta un array de strings. También puede incluir otras banderas de Chrome (por ejemplo,["--no-sandbox", "--disable-gpu"]). La bandera--no-sandboxsolo es necesaria en Linux — los perfiles de Windows y macOS no la necesitan.
Este ejemplo supone que el script se ejecuta en el mismo servidor que MoreLogin. Para escenarios remotos, consulte las notas después del código.
import requests
from playwright.sync_api import sync_playwright
# ── Configuration ──────────────────────────────────────────
# Local: script runs on the SAME server as MoreLogin
# Remote: script runs on a DIFFERENT machine — see notes below
API_BASE = "http://127.0.0.1:40000"
# ① Create a browser profile
resp = requests.post(f"{API_BASE}/api/env/create/quick", json={
"browserTypeId": 1,
"operatorSystemId": 5,
"quantity": 1
})
resp_data = resp.json()
assert resp_data["code"] == 0, f"Create failed: {resp_data}"
env_id = resp_data["data"]["envIds"][0]
print(f"✅ Created profile: {env_id}")
# ①-b Add --no-sandbox (required on Linux Server)
resp = requests.post(f"{API_BASE}/api/env/update", json={
"envId": env_id,
"startupParams": ["--no-sandbox"]
})
resp_data = resp.json()
assert resp_data["code"] == 0, f"Update failed: {resp_data}"
print(f"✅ Set --no-sandbox for profile: {env_id}")
# ② Start the profile (headless)
resp = requests.post(f"{API_BASE}/api/env/start", json={
"envId": env_id
})
resp_data = resp.json()
assert resp_data["code"] == 0, f"Start failed: {resp_data}"
debug_port = resp_data["data"]["debugPort"] # Dynamic — different for each profile
print(f"✅ Started — debug port: {debug_port}")
# ③ Build the CDP URL
cdp_url = f"http://127.0.0.1:{debug_port}"
# ④ Connect via CDP and automate
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
page = browser.contexts[0].pages[0]
page.goto("https://www.google.com")
page.screenshot(path=f"screenshot_{env_id}.png")
print(f"✅ Screenshot saved")
# Use disconnect() — not close() — to detach without killing the browser.
# The profile will be stopped cleanly via the API in step ⑤.
browser.disconnect()
# ⑤ Stop the profile
requests.post(f"{API_BASE}/api/env/close", json={"envId": env_id})
print(f"✅ Profile stopped")
# ⑥ Delete the profile
requests.post(f"{API_BASE}/api/env/remove", json={"envIds": [env_id]})
print(f"✅ Profile deleted")[!NOTE] ¿Se ejecuta desde una máquina remota? Dos enfoques:
Opción A: túnel SSH (recomendado): Configure túneles SSH desde su máquina local al servidor (consulte § 4.4), luego mantenga
API_BASE = "http://127.0.0.1:40000"ycdp_url = f"http://127.0.0.1:{debug_port}": SSH hace que los puertos remotos parezcan locales.Opción B: socat en el servidor: En el servidor, inicie el reenvío socat para el puerto API y para cada puerto CDP:
# Ejecútelos en el SERVIDOR, no en su máquina local socat TCP-LISTEN:40001,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:40000 & socat TCP-LISTEN:$((debug_port+1)),fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:$debug_port &Luego, en su secuencia de comandos, configure
API_BASE = "http://<server-ip>:40001"ycdp_url = f"http://<server-ip>:{debug_port + 1}". ⚠️ Restringir el acceso con reglas de firewall: consulte § 4.3.
[!IMPORTANT] La estructura
resp.json()["data"]["envIds"]coincide con el formato de respuesta/api/env/create/quickactual. Si encuentra una forma diferente (por ejemplo,data: ["id1", ...]), consulte la Referencia de API para su versión; los formatos de respuesta pueden variar según la versión.
Se obtuvieron los siguientes resultados en una máquina virtual de servidor Ubuntu 24.04 (8 vCPU, 8 GB de RAM) utilizando el script de prueba de esfuerzo completo:
| Métrica | Valor |
|---|---|
| Ejecuciones totales | 100 |
| Simultaneidad | 4 (simultáneo) |
| Tasa de éxito | 100,0% |
| Tiempo total | 604,06 segundos |
| Tiempo promedio por tarea | 6,04 segundos |
| Rendimiento | 0,17 tareas/s |
Estos números sirven como punto de referencia. El rendimiento real depende de las especificaciones del servidor, las condiciones de la red y la complejidad de la página.
Para servidores de producción, ejecute MoreLogin como un servicio systemd para obtener un inicio automático al arrancar, reiniciar en caso de falla y un registro centralizado.
sudo tee /etc/systemd/system/morelogin.service > /dev/null <<'EOF'
[Unit]
Description=MoreLogin Browser (headless)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/morelogin
ExecStart=/usr/bin/xvfb-run -a /opt/morelogin/MoreLogin_x86_64_2.54.0.AppImage --no-sandbox
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOFAjuste las rutas
WorkingDirectoryyExecStartpara que coincidan con el lugar donde colocó la AppImage.
[!TIP] Para producción, considere crear un usuario dedicado (por ejemplo,
morelogin) en lugar de ejecutarlo comorooty ajuste la propiedad y los permisos del archivo en consecuencia. Si AppImage actualmente requiere privilegios de root, puede conservarUser=root, pero aislar el proceso en una cuenta que no sea root es una buena práctica.
sudo systemctl daemon-reload
sudo systemctl enable morelogin # Auto-start on boot
sudo systemctl start morelogin # Start nowsudo systemctl status morelogin # Check status
sudo journalctl -u morelogin -f # Stream logs
sudo systemctl restart morelogin # Restart
sudo systemctl stop morelogin # Stop[!NOTE] Después de reiniciar, debe volver a llamar al punto final de inicio de sesión; la sesión API no sobrevive a los reinicios del proceso. Para una recuperación automatizada, considere agregar un script
ExecStartPosto un trabajo cron de verificación de estado que llame al punto final de inicio de sesión después de que se inicie el servicio.
AppImages require FUSE to run.Solución: Instalar soporte FUSE:
sudo apt install -y libfuse2t64Solución: Instale el paquete de fuentes para el idioma de destino (consulte Paso 1: Instalar fuentes).
Causa: Los puertos de depuración de CDP se vinculan a 127.0.0.1 de forma predeterminada.
Solución: Configure el reenvío socat (consulte el Paso 4) y asegúrese de que las reglas del firewall permitan el puerto reenviado.
Causa: MoreLogin aún no ha terminado de iniciarse o el proceso falló.
Arreglo:
- Espere de 5 a 10 segundos después del inicio
- Verifique
morelogin.logpara ver si hay errores - Verifique que el proceso se esté ejecutando:
ps aux | grep MoreLogin
{"status": "error", "code": 401, "message": "Your login status has expired, please log in again"}Causa: No has iniciado sesión a través de la API o se reinició el proceso MoreLogin.
Solución: Llame al punto final de inicio de sesión antes de cualquier otra llamada API (consulte el Paso 3).
| Objetivo | Enlace |
|---|---|
| Referencia completa de la API del navegador | API del navegador |
| Configuración de autenticación | Guía de autenticación |
| Ejemplos de Playwright / Selenium / Puppeteer | Ejemplos de automatización |
| Script completo de prueba de estrés de Linux | GitHub — linux_server_test.py |
| Inicio rápido de CLI | Guía CLI |