# Implantação de servidor Linux

Deploy MoreLogin on a headless Ubuntu server and automate browser profiles via the Local API — no desktop environment required.

## O que você alcançará

Ao final deste guia você terá:

1. A running MoreLogin instance on an Ubuntu 24.04 headless server
2. Network forwarding configured so external machines can connect via CDP (Chrome DevTools Protocol)
3. A working Python automation script that creates, launches, controls, and cleans up browser profiles


## Visão geral da arquitetura

```
┌──────────────────────────────────────────────────────────┐
│                    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]
The CDP debug port is **dynamic** — each browser profile gets its own port, returned by the `/api/env/start` endpoint. The diagram above uses `<N>` as a placeholder.


## Pré-requisitos

| Requisito | Detalhes |
|  --- | --- |
| **Sistema operacional** | Ubuntu 24.04 Server (x86_64) |
| **Especificações recomendadas** | 8 vCPU, 8 GB RAM (supports ~5 concurrent profiles) |
| **Rede** | Acesso de saída à Internet; open inbound port `40001` and the forwarded CDP ports you choose, or use SSH tunnels instead |
| **Python** (opcional) | Python 3.8+ with `pip` for running the example script |


## Passo 1 — Instalar dependências do sistema

Connect to your server via SSH and install the required packages:

```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 fontes (opcional)

If browser pages render without text or show missing characters, install the corresponding font packages:

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

> For other languages, install the matching [Noto font family](https://fonts.google.com/noto) package.


## Passo 2 — Baixe e inicie maisLogin

### 2.1 Baixe o 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
```

> Replace `2.54.0` with the latest version available from your MoreLogin account or the [download page](https://www.morelogin.com/download/).


### 2.2 Iniciar mais Login em segundo plano

Use `xvfb-run` to provide a virtual display, then run the AppImage:

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

Verifique se foi iniciado com sucesso:

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

> The process may take 5–10 seconds to fully initialize.


## Step 3 — Log In to MoreLogin via API (Required)

> [!CAUTION]
**Você deve fazer login antes de chamar qualquer outro endpoint da API local.** Em um servidor headless, não há GUI para fazer login manualmente, portanto, você deve autenticar por meio da API. Sem esta etapa, todas as chamadas de API retornarão:

```json
{"status": "error", "code": 401, "message": "Your login status has expired, please log in again"}
```


### 3.1 Obtenha suas credenciais de API

Open the MoreLogin desktop client (on any machine where you're logged in) and navigate to **Settings → API & MCP**. Copy the **APP ID** and **API Key** from the **Open API** section:

![MoreLogin API Settings — Copy APP ID and API Key from the Open API section](/assets/image.cfac9a4c31ae47e8434739e42cab4601ee08d737bba4fccba40f2f3bc78e9648.282e0fcf.png)

### 3.2 Faça login via curl

Chame o endpoint de login com suas credenciais:

```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"
  }'
```

Uma resposta bem-sucedida é semelhante a:

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

### 3.3 Verifique o login

Confirm the API is ready by listing browser profiles:

```bash
curl -s -X POST http://127.0.0.1:40000/api/env/page \
  -H "Content-Type: application/json" \
  -d '{"pageNo": 1, "pageSize": 1}'
```

> A `{"code":0, ...}` response means you are logged in and the API is ready.


> **Checkpoint:** Your MoreLogin server is fully operational. Proceed to [Step 4](#step-4--configure-network-forwarding-socat) for remote access, or jump directly to [Step 5](#step-5--quick-automation-example) if running scripts on the same server.


> [!NOTE]
The login session persists as long as the MoreLogin process is running. If you restart the AppImage, you will need to log in again.


## Passo 4 — Configurar o encaminhamento de rede (socat)

By default, both the Local API (`:40000`) and CDP debug ports bind to `127.0.0.1`. If you need to access them from an external machine (e.g., your development laptop), use `socat` to forward traffic.

> [!WARNING]
**Security risk — do not expose these ports to the public internet.**
- The Local API has **no built-in authentication** for most endpoints.
- A CDP debug port grants **full remote control** of the browser instance (read cookies, inject scripts, capture screenshots).

**Recomendações:**
- Use an **SSH tunnel** instead of socat for remote access: `ssh -L 40000:127.0.0.1:40000 user@server`
- If you must use socat, restrict access with firewall rules to **specific IPs only**
- Use a **VPN** or cloud provider security groups to limit inbound traffic
- **Never** open ports `40001` / CDP ports to `0.0.0.0` on a public-facing server without IP restrictions



### 4.1 Encaminhar a porta API local

```bash
nohup socat TCP-LISTEN:40001,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:40000 &
```

> External machines can now reach the API at `http://<server-ip>:40001`.


### 4.2 Portas de depuração CDP de encaminhamento

When you start a browser profile via the API, the response includes a **dynamic** `debugPort` (e.g., `9222`). Cada perfil pode receber uma porta diferente. Forward it so external automation tools (Playwright, Puppeteer, Selenium) can connect:

```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]
When running multiple profiles concurrently, ensure forwarded ports do not collide with other profiles' debug ports. For example, if profile A gets `debugPort=9222` and you forward to `9223`, but profile B receives `debugPort=9223`, there will be a port conflict. Consider using a larger offset or a dedicated port range.


> [!TIP]
In production, create socat forwarding **dynamically** after each `/api/env/start` call, using the returned `debugPort`. See the [Python example](#52-create--start--automate--cleanup) for a working implementation.


> If running automation scripts **on the same server**, you can skip socat and connect directly to `127.0.0.1`.


### 4.3 Abrir portas de firewall

If you use socat, restrict access to trusted IPs only:

```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: use o túnel SSH

For the most secure remote access, use an SSH tunnel — no firewall changes or socat needed.

Because the CDP port is **dynamic** (assigned when you start a profile), the workflow is:

1. **Túnel a porta da API primeiro:**

```bash
# Run this on your local machine
ssh -L 40000:127.0.0.1:40000 user@<server-ip>
```
2. **Start the profile** via the tunneled API (`http://127.0.0.1:40000/api/env/start`) and read the returned `debugPort`.
3. **Abra um segundo túnel para a porta CDP:**

```bash
# Replace <debugPort> with the actual port returned by the API
ssh -L <debugPort>:127.0.0.1:<debugPort> user@<server-ip>
```
4. **Connect** to `http://127.0.0.1:<debugPort>` from your local Playwright / Puppeteer scripts as if the server were local.


> [!TIP]
You can combine both tunnels in one command if you know the port range in advance, e.g.:

```bash
ssh -L 40000:127.0.0.1:40000 -L 9222:127.0.0.1:9222 -L 9223:127.0.0.1:9223 user@<server-ip>
```
But in practice it's easier to start the API tunnel first, then add per-profile tunnels as needed.


## Passo 5 — Exemplo de automação rápida

Below is a minimal Python example showing the full lifecycle of a browser profile. For the complete production-ready script with concurrency and error handling, see the [full example on GitHub](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py).

### 5.1 Instalar dependências do Python

```bash
pip install requests playwright
```

> Playwright is used here only for its CDP client (`connect_over_cdp`). You do **not** need to run `playwright install` — MoreLogin provides its own browser.


### 5.2 Criar → Iniciar → Automatizar → Limpeza

This example assumes the script runs **on the same server** as MoreLogin. For remote scenarios, see the notes after the code.

```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]
**Running from a remote machine?** Two approaches:
**Opção A — túnel SSH (recomendado):**
Configure túneis SSH da sua máquina local para o servidor (consulte [§ 4.4](#44-recommended-use-ssh-tunnel-instead)) e mantenha `API_BASE = "http://127.0.0.1:40000"` e `cdp_url = f"http://127.0.0.1:{debug_port}"` — o SSH faz com que as portas remotas pareçam locais.
**Opção B — socat no servidor:**
On the **server**, start socat forwarding for the API port and for each CDP port:

```bash
# Run these on the SERVER, not on your local machine
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 &
```
Then in your script, set `API_BASE = "http://<server-ip>:40001"` and `cdp_url = f"http://<server-ip>:{debug_port + 1}"`.
⚠️ Restrict access with firewall rules — see [§ 4.3](#43-open-firewall-ports).


> [!IMPORTANT]
The `resp.json()["data"]["envIds"]` structure matches the current `/api/env/create/quick` response format. Se você encontrar um formato diferente (por exemplo, `data: ["id1", ...]`), verifique a [Referência da API](/pt/api-reference/browser) da sua versão. Os formatos de resposta podem variar entre as versões.


## Referência de desempenho

The following results were obtained on an Ubuntu 24.04 Server VM (8 vCPU, 8 GB RAM) using the [full stress test script](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py):

| Métrica | Valor |
|  --- | --- |
| **Total de corridas** | 100 |
| **Simultaneidade** | 4 (simultâneo) |
| **Taxa de sucesso** | 100,0% |
| **Tempo total** | 604,06s |
| **Tempo médio por tarefa** | 6,04s |
| **Rendimento** | 0,17 tarefas/s |


> Esses números servem como base. Actual performance depends on server specs, network conditions, and page complexity.


## Implantação de produção (systemd)

For production servers, run MoreLogin as a **systemd service** to get automatic startup on boot, restart on crash, and centralized logging.

### Crie o arquivo de serviço

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

> Adjust `WorkingDirectory` and `ExecStart` paths to match where you placed the AppImage.


> [!TIP]
Para produção, considere criar um usuário dedicado (por exemplo, `morelogin`) em vez de executar como `root` e ajuste a propriedade e as permissões do arquivo de acordo. Se o AppImage atualmente exigir privilégios de root, você poderá manter `User=root`, mas isolar o processo em uma conta não root é uma prática recomendada.


### Habilitar e iniciar

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

### Gerenciar o serviço

```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]
After a restart, you must call the [login endpoint](#32-log-in-via-curl) again — the API session does not survive process restarts. For automated recovery, consider adding an `ExecStartPost` script or a health-check cron job that calls the login endpoint after the service starts.


## Solução de problemas

### MoreLogin não inicia

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

**Correção:** Instale o suporte FUSE:

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

### Browser pages show blank text / missing characters

**Fix:** Install the font package for the target language (see [Step 1 — Install Fonts](#install-fonts-optional)).

### Conexão CDP recusada pela máquina externa

**Cause:** CDP debug ports bind to `127.0.0.1` by default.

**Fix:** Set up socat forwarding (see [Step 4](#step-4--configure-network-forwarding-socat)) and ensure firewall rules allow the forwarded port.

### `curl` to Local API returns "Connection refused"

**Cause:** MoreLogin hasn't finished starting yet, or the process crashed.

**Correção:**

1. Aguarde 5 a 10 segundos após a inicialização
2. Verifique se há erros no `morelogin.log`
3. Verifique se o processo está em execução: `ps aux | grep MoreLogin`


### API retorna 401 “status de login expirou”

```json
{"status": "error", "code": 401, "message": "Your login status has expired, please log in again"}
```

**Cause:** You haven't logged in via the API, or the MoreLogin process was restarted.

**Fix:** Call the login endpoint before any other API call (see [Step 3](#step-3--log-in-to-morelogin-via-api-required)).

## Próximas etapas

| Objetivo | Ligação |
|  --- | --- |
| Referência completa da API do navegador | [API do navegador](/pt/api-reference/browser) |
| Configuração de autenticação | [Guia de autenticação](/pt/api-reference/getting-started/authentication) |
| Exemplos de dramaturgo / selênio / titereiro | [Exemplos de automação](/pt/api-reference/examples) |
| Script completo de teste de estresse do Linux | [GitHub — linux_server_test.py](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py) |
| Início rápido da CLI | [Guia CLI](/pt/cli/quick-start) |