# Triển khai máy chủ Linux

Triển khai MoreLogin trên máy chủ Ubuntu không đầu và tự động hóa cấu hình trình duyệt thông qua API cục bộ - không cần môi trường máy tính để bàn.

## Những gì bạn sẽ đạt được

Đến cuối hướng dẫn này, bạn sẽ có:

1. Một phiên bản MoreLogin đang chạy trên máy chủ không đầu Ubuntu 24.04
2. Chuyển tiếp mạng được định cấu hình để các máy bên ngoài có thể kết nối qua CDP (Giao thức Chrome DevTools)
3. Tập lệnh tự động hóa Python đang hoạt động để tạo, khởi chạy, điều khiển và dọn dẹp cấu hình trình duyệt


## Tổng quan về kiến trúc

```
┌──────────────────────────────────────────────────────────┐
│                    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]
Cổng gỡ lỗi CDP **động** — mỗi cấu hình trình duyệt có cổng riêng, được trả về bởi điểm cuối `/api/env/start`. Sơ đồ trên sử dụng `<N>` làm phần giữ chỗ.


## Điều kiện tiên quyết

| Yêu cầu | Chi tiết |
|  --- | --- |
| **Hệ điều hành** | Máy chủ Ubuntu 24.04 (x86_64) |
| **Thông số kỹ thuật được đề xuất** | 8 vCPU, RAM 8 GB (hỗ trợ ~5 cấu hình đồng thời) |
| **Mạng** | Truy cập internet bên ngoài; mở cổng vào `40001` và các cổng CDP được chuyển tiếp mà bạn chọn hoặc thay vào đó hãy sử dụng đường hầm SSH |
| **Python** (tùy chọn) | Python 3.8+ với `pip` để chạy tập lệnh mẫu |


## Bước 1 - Cài đặt phụ thuộc hệ thống

Kết nối với máy chủ của bạn thông qua SSH và cài đặt các gói cần thiết:

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

### Cài đặt phông chữ (Tùy chọn)

Nếu các trang trình duyệt hiển thị không có văn bản hoặc hiển thị các ký tự bị thiếu, hãy cài đặt các gói phông chữ tương ứng:

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

> Đối với các ngôn ngữ khác, hãy cài đặt gói [Họ phông chữ Noto](https://fonts.google.com/noto) phù hợp.


## Bước 2 - Tải xuống và khởi chạy ThêmĐăng nhập

### 2.1 Tải xuống hình ảnh ứng dụng

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

> Thay thế `2.54.0` bằng phiên bản mới nhất có sẵn từ tài khoản MoreLogin của bạn hoặc [trang tải xuống](https://www.morelogin.com/download/).


### 2.2 Bắt đầu thêmĐăng nhập trong nền

Sử dụng `xvfb-run` để cung cấp màn hình ảo, sau đó chạy AppImage:

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

Xác minh nó đã bắt đầu thành công:

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

> Quá trình này có thể mất 5–10 giây để khởi tạo hoàn toàn.


## Bước 3 - Đăng nhập vào MoreLogin qua API (Bắt buộc)

> [!CAUTION]
**Bạn phải đăng nhập trước khi gọi bất kỳ điểm cuối API cục bộ nào khác.** Trên máy chủ không đầu không có GUI để đăng nhập theo cách thủ công, vì vậy bạn phải xác thực qua API. Nếu không có bước này, tất cả lệnh gọi API sẽ trả về:

```json
{"status": "error", "code": 401, "message": "Trạng thái đăng nhập của bạn đã hết hạn, vui lòng đăng nhập lại"}
```


### 3.1 Nhận thông tin xác thực API của bạn

Mở ứng dụng khách máy tính để bàn MoreLogin (trên bất kỳ máy nào bạn đã đăng nhập) và điều hướng đến **Cài đặt → API & MCP**. Sao chép **ID ỨNG DỤNG** và **Khóa API** từ phần **Mở API**:

![Cài đặt API đăng nhập nhiều hơn — Sao chép ID ứng dụng và khóa API từ phần API mở](/assets/image.cfac9a4c31ae47e8434739e42cab4601ee08d737bba4fccba40f2f3bc78e9648.35e5403d.png)

### 3.2 Đăng nhập qua cuộn tròn

Gọi điểm cuối đăng nhập bằng thông tin đăng nhập của bạn:

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

Một phản hồi thành công trông giống như:

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

### 3.3 Xác minh thông tin đăng nhập

Xác nhận API đã sẵn sàng bằng cách liệt kê hồ sơ trình duyệt:

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

> Phản hồi `{"code":0, ...}` có nghĩa là bạn đã đăng nhập và API đã sẵn sàng.


> **Điểm kiểm tra:** Máy chủ MoreLogin của bạn đã hoạt động đầy đủ. Hãy tiếp tục tới [Bước 4](#step-4--configure-network-forwarding-socat) để truy cập từ xa hoặc chuyển thẳng tới [Bước 5](#step-5--quick-automation-example) nếu chạy tập lệnh trên cùng một máy chủ.


> [!NOTE]
Phiên đăng nhập vẫn tiếp tục miễn là quá trình MoreLogin đang chạy. Nếu khởi động lại AppImage, bạn sẽ cần phải đăng nhập lại.


## Bước 4 - Định cấu hình Chuyển tiếp mạng (socat)

Theo mặc định, cả cổng gỡ lỗi API cục bộ (`:40000`) và CDP đều liên kết với `127.0.0.1`. Nếu bạn cần truy cập chúng từ máy bên ngoài (ví dụ: máy tính xách tay phát triển của bạn), hãy sử dụng `socat` để chuyển tiếp lưu lượng truy cập.

> [!WARNING]
**Rủi ro bảo mật — không để các cổng này tiếp xúc với Internet công cộng.**
- API cục bộ **không có tính năng xác thực tích hợp** cho hầu hết các điểm cuối.
- Cổng gỡ lỗi CDP cấp **toàn quyền điều khiển từ xa** phiên bản trình duyệt (đọc cookie, chèn tập lệnh, chụp ảnh màn hình).

**Khuyến nghị:**
- Sử dụng **đường hầm SSH** thay vì socat để truy cập từ xa: `ssh -L 40000:127.0.0.1:40000 user@server`
- Nếu bạn phải sử dụng socat, hãy hạn chế quyền truy cập bằng quy tắc tường lửa đối với **chỉ các IP cụ thể**
- Sử dụng **VPN** hoặc nhóm bảo mật của nhà cung cấp dịch vụ đám mây để hạn chế lưu lượng truy cập vào
- **Không bao giờ** mở cổng `40001` / CDP tới `0.0.0.0` trên máy chủ công khai mà không có giới hạn IP



### 4.1 Chuyển tiếp cổng API cục bộ

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

> Máy bên ngoài hiện có thể tiếp cận API tại `http://<server-ip>:40001`.


### 4.2 Chuyển tiếp cổng gỡ lỗi CDP

Khi bạn khởi động cấu hình trình duyệt qua API, phản hồi sẽ bao gồm **động** `debugPort` (ví dụ: `9222`). Mỗi hồ sơ có thể nhận được một cổng khác nhau. Chuyển tiếp nó để các công cụ tự động hóa bên ngoài (Playwright, Puppeteer, Selenium) có thể kết nối:

```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]
Khi chạy đồng thời nhiều cấu hình, hãy đảm bảo các cổng chuyển tiếp không xung đột với các cổng gỡ lỗi của cấu hình khác. Ví dụ: nếu cấu hình A nhận được `debugPort=9222` và bạn chuyển tiếp tới `9223` nhưng cấu hình B nhận được `debugPort=9223` thì sẽ xảy ra xung đột cổng. Hãy cân nhắc sử dụng khoảng chênh lệch lớn hơn hoặc phạm vi cổng chuyên dụng.


> [!TIP]
Trong quá trình sản xuất, hãy tạo chuyển tiếp socat **động** sau mỗi cuộc gọi `/api/env/start`, sử dụng `debugPort` được trả về. Xem [ví dụ về Python](#52-create--start--automate--cleanup) để biết cách triển khai hoạt động.


> Nếu chạy tập lệnh tự động hóa **trên cùng một máy chủ**, bạn có thể bỏ qua socat và kết nối trực tiếp với `127.0.0.1`.


### 4.3 Mở cổng tường lửa

Nếu bạn sử dụng socat, chỉ hạn chế quyền truy cập vào các IP đáng tin cậy:

```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 Khuyến nghị: Thay vào đó hãy sử dụng Đường hầm SSH

Để truy cập từ xa an toàn nhất, hãy sử dụng đường hầm SSH — không cần thay đổi tường lửa hoặc socat.

Vì cổng CDP là **động** (được chỉ định khi bạn khởi động cấu hình) nên quy trình làm việc là:

1. **Trước tiên hãy đào cổng API:**

```bash
# Run this on your local machine
ssh -L 40000:127.0.0.1:40000 user@<server-ip>
```
2. **Bắt đầu cấu hình** qua API được tạo đường hầm (`http://127.0.0.1:40000/api/env/start`) và đọc `debugPort` được trả về.
3. **Mở đường hầm thứ hai cho cổng CDP:**

```bash
# Replace <debugPort> with the actual port returned by the API
ssh -L <debugPort>:127.0.0.1:<debugPort> user@<server-ip>
```
4. **Kết nối** với `http://127.0.0.1:<debugPort>` từ tập lệnh Nhà viết kịch / Người múa rối cục bộ của bạn như thể máy chủ là cục bộ.


> [!TIP]
Bạn có thể kết hợp cả hai đường hầm trong một lệnh nếu bạn biết trước phạm vi cổng, ví dụ:

```
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>
```
Nhưng trên thực tế, việc khởi động đường hầm API trước sẽ dễ dàng hơn, sau đó thêm đường hầm theo từng cấu hình nếu cần.


## Bước 5 - Ví dụ về tự động hóa nhanh

Dưới đây là ví dụ Python tối thiểu hiển thị toàn bộ vòng đời của cấu hình trình duyệt. Để biết tập lệnh hoàn chỉnh sẵn sàng sản xuất có tính năng xử lý đồng thời và lỗi, hãy xem [ví dụ đầy đủ trên GitHub](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py).

### 5.1 Cài đặt phụ thuộc Python

```bash
pip install requests playwright
```

> Nhà viết kịch chỉ được sử dụng ở đây cho ứng dụng khách CDP (`connect_over_cdp`). Bạn **không** cần chạy `playwright install` — MoreLogin cung cấp trình duyệt riêng.


### 5.2 Tạo → Bắt đầu → Tự động hóa → Dọn dẹp

Ví dụ này giả định tập lệnh chạy **trên cùng một máy chủ** với MoreLogin. Đối với các kịch bản từ xa, hãy xem ghi chú sau mã.

```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]
**Chạy từ máy từ xa?** Hai cách tiếp cận:
**Tùy chọn A — Đường hầm SSH (được khuyến nghị):**
Thiết lập đường hầm SSH từ máy cục bộ của bạn đến máy chủ (xem [§ 4.4](#44-recommended-use-ssh-tunnel-instead)), sau đó giữ `API_BASE = "http://127.0.0.1:40000"` và `cdp_url = f"http://127.0.0.1:{debug_port}"` — SSH làm cho các cổng từ xa xuất hiện cục bộ.
**Tùy chọn B — socat trên máy chủ:**
Trên **máy chủ**, bắt đầu chuyển tiếp socat cho cổng API và cho mỗi cổng CDP:

```
# Chạy chúng trên MÁY CHỦ, không phải trên máy cục bộ của bạn
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 &
```
Sau đó, trong tập lệnh của bạn, hãy đặt `API_BASE = "http://<server-ip>:40001"` và `cdp_url = f"http://<server-ip>:{debug_port + 1}"`.
⚠️ Hạn chế quyền truy cập bằng quy tắc tường lửa — xem [§ 4.3](#43-open-firewall-ports).


> [!IMPORTANT]
Cấu trúc `resp.json()["data"]["envIds"]` khớp với định dạng phản hồi `/api/env/create/quick` hiện tại. Nếu bạn gặp một hình dạng khác (ví dụ: `data: ["id1", ...]`), hãy kiểm tra [Tham khảo API](/vi/api-reference/browser) cho phiên bản của bạn — định dạng phản hồi có thể khác nhau giữa các bản phát hành.


## Điểm chuẩn hiệu suất

Các kết quả sau đây thu được trên máy ảo Ubuntu 24.04 Server (8 vCPU, 8 GB RAM) bằng cách sử dụng [tập lệnh kiểm tra mức độ căng thẳng đầy đủ](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py):

| Số liệu | Giá trị |
|  --- | --- |
| **Tổng số lượt chạy** | 100 |
| **Đồng thời** | 4 (đồng thời) |
| **Tỷ lệ thành công** | 100,0% |
| **Tổng thời gian** | 604,06 giây |
| **Thời gian trung bình cho mỗi nhiệm vụ** | 6,04 giây |
| **Thông lượng** | 0,17 nhiệm vụ/giây |


> Những con số này phục vụ như là một đường cơ sở. Hiệu suất thực tế phụ thuộc vào thông số kỹ thuật của máy chủ, điều kiện mạng và độ phức tạp của trang.


## Triển khai sản xuất (systemd)

Đối với các máy chủ sản xuất, hãy chạy MoreLogin dưới dạng **dịch vụ systemd** để tự động khởi động khi khởi động, khởi động lại khi gặp sự cố và ghi nhật ký tập trung.

### Tạo tệp dịch vụ

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

> Điều chỉnh đường dẫn `WorkingDirectory` và `ExecStart` để khớp với vị trí bạn đã đặt AppImage.


> [!TIP]
Đối với sản xuất, hãy cân nhắc việc tạo người dùng chuyên dụng (ví dụ: `morelogin`) thay vì chạy dưới dạng `root` và điều chỉnh quyền sở hữu cũng như quyền đối với tệp cho phù hợp. Nếu AppImage hiện yêu cầu đặc quyền root thì bạn có thể giữ `User=root` nhưng cách ly quy trình trong tài khoản không phải root là cách tốt nhất.


### Kích hoạt và bắt đầu

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

### Quản lý dịch vụ

```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]
Sau khi khởi động lại, bạn phải gọi lại [điểm cuối đăng nhập](#32-log-in-via-curl) — phiên API không tồn tại trong quá trình khởi động lại. Để khôi phục tự động, hãy cân nhắc thêm tập lệnh `ExecStartPost` hoặc công việc định kỳ kiểm tra tình trạng gọi điểm cuối đăng nhập sau khi dịch vụ khởi động.


## Khắc phục sự cố

### ThêmĐăng nhập không khởi động được

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

**Khắc phục:** Cài đặt hỗ trợ FUSE:

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

### Các trang trình duyệt hiển thị văn bản trống/ký tự bị thiếu

**Khắc phục:** Cài đặt gói phông chữ cho ngôn ngữ đích (xem [Bước 1 — Cài đặt phông chữ](#install-fonts-optional)).

### Kết nối CDP bị từ chối từ máy bên ngoài

**Lý do:** Cổng gỡ lỗi CDP liên kết với `127.0.0.1` theo mặc định.

**Khắc phục:** Thiết lập chuyển tiếp socat (xem [Bước 4](#step-4--configure-network-forwarding-socat)) và đảm bảo quy tắc tường lửa cho phép cổng chuyển tiếp.

### `curl` tới API cục bộ trả về "Kết nối bị từ chối"

**Lý do:** MoreLogin chưa khởi động xong hoặc quá trình bị lỗi.

**Sửa chữa:**

1. Đợi 5–10 giây sau khi khởi động
2. Kiểm tra `morelogin.log` để tìm lỗi
3. Xác minh quy trình đang chạy: `ps aux | grep MoreLogin`


### API trả về 401 "trạng thái đăng nhập đã hết hạn"

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

**Lý do:** Bạn chưa đăng nhập qua API hoặc quá trình MoreLogin đã được khởi động lại.

**Khắc phục:** Gọi điểm cuối đăng nhập trước bất kỳ lệnh gọi API nào khác (xem [Bước 3](#step-3--log-in-to-morelogin-via-api-required)).

## Các bước tiếp theo

| Mục tiêu | liên kết |
|  --- | --- |
| Tài liệu tham khảo API trình duyệt đầy đủ | [API trình duyệt](/vi/api-reference/browser) |
| Thiết lập xác thực | [Hướng dẫn xác thực](/vi/api-reference/getting-started/authentication) |
| Ví dụ về nhà viết kịch / Selenium / Puppeteer | [Ví dụ về tự động hóa](/vi/api-reference/examples) |
| Hoàn thành tập lệnh kiểm tra căng thẳng Linux | [GitHub — linux_server_test.py](https://github.com/MoreLoginBrowser/MoreLogin-API-Demos/blob/main/MoreLogin-Python/linux_server_test.py) |
| CLI bắt đầu nhanh | [Hướng dẫn CLI](/vi/cli/quick-start) |