# Implementación del servidor Linux

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.

## Lo que lograrás

Al final de esta guía tendrás:

1. Una instancia de MoreLogin en ejecución en un servidor sin cabeza Ubuntu 24.04
2. Reenvío de red configurado para que las máquinas externas puedan conectarse a través de CDP (Protocolo Chrome DevTools)
3. Un script de automatización de Python funcional que crea, inicia, controla y limpia perfiles del navegador.


## Descripción general de la arquitectura

```
┌──────────────────────────────────────────────────────────┐
│                    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.


## Requisitos previos

| 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 |


## Paso 1: instalar las dependencias del sistema

Conéctese a su servidor a través de SSH e instale los paquetes requeridos:

```bash
# 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 socat
```

### Instalar fuentes (opcional)

Si las páginas del navegador se muestran sin texto o muestran caracteres faltantes, instale los paquetes de fuentes correspondientes:

```bash
# 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-extra
```

> Para otros idiomas, instale el paquete [familia de fuentes Noto](https://fonts.google.com/noto) correspondiente.


## Paso 2: Descargar y ejecutar MásIniciar sesión

### 2.1 Descargar la AppImage

```bash
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.AppImage
```

> Reemplace `2.54.0` con la última versión disponible en su cuenta MoreLogin o en la [página de descarga](https://www.morelogin.com/download/).


### 2.2 Comenzar másIniciar sesión en segundo plano

Utilice `xvfb-run` para proporcionar una pantalla virtual, luego ejecute AppImage:

```bash
nohup xvfb-run -a ./MoreLogin_x86_64_2.54.0.AppImage --no-sandbox > morelogin.log 2>&1 &
```

Verifique que haya comenzado exitosamente:

```bash
# Check the process is running
ps aux | grep MoreLogin
```

> El proceso puede tardar entre 5 y 10 segundos en inicializarse por completo.


## Paso 3: inicie sesión en MoreLogin mediante API (obligatorio)

> [!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:

```json
{"status": "error", "code": 401, "message": "Su estado de inicio de sesión ha caducado, inicie sesión nuevamente"}
```


### 3.1 Obtenga sus credenciales API

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**:

![Más configuración de API de inicio de sesión: copie el ID de la aplicación y la clave de API de la sección Abrir API](/assets/image.cfac9a4c31ae47e8434739e42cab4601ee08d737bba4fccba40f2f3bc78e9648.81141750.png)

### 3.2 Iniciar sesión mediante curl

Llame al punto final de inicio de sesión con sus credenciales:

```bash
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:

```json
{"code": 0, "msg": null, "data": true}
```

### 3.3 Verificar el inicio de sesión

Confirme que la API esté lista enumerando los perfiles del navegador:

```bash
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](#step-4--configure-network-forwarding-socat) para obtener acceso remoto o vaya directamente al [Paso 5](#step-5--quick-automation-example) 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.


## Paso 4: configurar el reenvío de red (socat)

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 a `0.0.0.0` en un servidor público sin restricciones de IP



### 4.1 Reenviar el puerto API local

```bash
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`.


### 4.2 Puertos de depuración CDP directos

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:

```bash
# 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=9222` y usted reenvía a `9223`, pero el perfil B recibe `debugPort=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 el `debugPort` devuelto. Consulte el [ejemplo de Python](#52-create--start--automate--cleanup) 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`.


### 4.3 Abrir puertos de firewall

Si usa socat, restrinja el acceso solo a direcciones IP confiables:

```bash
# 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/tcp
```

### 4.4 Recomendado: utilice el túnel SSH en su lugar

Para 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:

1. **Primero canalice el puerto API:**

```bash
# Run this on your local machine
ssh -L 40000:127.0.0.1:40000 user@<server-ip>
```
2. **Inicie el perfil** a través de la API tunelizada (`http://127.0.0.1:40000/api/env/start`) y lea el `debugPort` devuelto.
3. **Abrir un segundo túnel para el puerto CDP:**

```bash
# Replace <debugPort> with the actual port returned by the API
ssh -L <debugPort>:127.0.0.1:<debugPort> user@<server-ip>
```
4. **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:

```golpecito
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.


## Paso 5: ejemplo de automatización rápida

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](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py).

### 5.1 Instalar dependencias de Python

```bash
pip install requests playwright
```

> Playwright se utiliza aquí solo para su cliente CDP (`connect_over_cdp`). **No** es necesario ejecutar `playwright install`: MoreLogin proporciona su propio navegador.


### 5.2 Crear → Iniciar → Automatizar → Limpiar

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.

```python
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": 1,
    "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}")


# ② 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](#44-recommended-use-ssh-tunnel-instead)), luego mantenga `API_BASE = "http://127.0.0.1:40000"` y `cdp_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:

```golpecito
# 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"` y `cdp_url = f"http://<server-ip>:{debug_port + 1}"`.
⚠️ Restringir el acceso con reglas de firewall: consulte [§ 4.3](#43-open-firewall-ports).


> [!IMPORTANT]
La estructura `resp.json()["data"]["envIds"]` coincide con el formato de respuesta `/api/env/create/quick` actual. Si encuentra una forma diferente (por ejemplo, `data: ["id1", ...]`), consulte la [Referencia de API](/es/api-reference/browser) para su versión; los formatos de respuesta pueden variar según la versión.


## Punto de referencia de rendimiento

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](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py):

| 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.


## Implementación de producción (systemd)

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.

### Crear el archivo de servicio

```bash
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
EOF
```

> Ajuste las rutas `WorkingDirectory` y `ExecStart` para 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 como `root` y ajuste la propiedad y los permisos del archivo en consecuencia. Si AppImage actualmente requiere privilegios de root, puede conservar `User=root`, pero aislar el proceso en una cuenta que no sea root es una buena práctica.


### Habilitar e iniciar

```bash
sudo systemctl daemon-reload
sudo systemctl enable morelogin    # Auto-start on boot
sudo systemctl start morelogin     # Start now
```

### Gestionar el servicio

```bash
sudo 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](#32-log-in-via-curl); la sesión API no sobrevive a los reinicios del proceso. Para una recuperación automatizada, considere agregar un script `ExecStartPost` o 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.


## Solución de problemas

### MásEl inicio de sesión no puede iniciarse

```
AppImages require FUSE to run.
```

**Solución:** Instalar soporte FUSE:

```bash
sudo apt install -y libfuse2t64
```

### Las páginas del navegador muestran texto en blanco o caracteres faltantes

**Solución:** Instale el paquete de fuentes para el idioma de destino (consulte [Paso 1: Instalar fuentes](#install-fonts-optional)).

### Conexión CDP rechazada desde una máquina externa

**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](#step-4--configure-network-forwarding-socat)) y asegúrese de que las reglas del firewall permitan el puerto reenviado.

### `curl` a la API local devuelve "Conexión rechazada"

**Causa:** MoreLogin aún no ha terminado de iniciarse o el proceso falló.

**Arreglo:**

1. Espere de 5 a 10 segundos después del inicio
2. Verifique `morelogin.log` para ver si hay errores
3. Verifique que el proceso se esté ejecutando: `ps aux | grep MoreLogin`


### API devuelve 401 "el estado de inicio de sesión ha caducado"

```json
{"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](#step-3--log-in-to-morelogin-via-api-required)).

## Próximos pasos

| Objetivo | Enlace |
|  --- | --- |
| Referencia completa de la API del navegador | [API del navegador](/es/api-reference/browser) |
| Configuración de autenticación | [Guía de autenticación](/es/api-reference/getting-started/authentication) |
| Ejemplos de Playwright / Selenium / Puppeteer | [Ejemplos de automatización](/es/api-reference/examples) |
| Script completo de prueba de estrés de Linux | [GitHub — linux_server_test.py](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py) |
| Inicio rápido de CLI | [Guía CLI](/es/cli/quick-start) |