Tài liệu PeerovaPeerova documentation

Peerova là tunnel P2P trực tiếp + SDK cho mọi giao thức TCP/UDP. Client nối thẳng tới dịch vụ của bạn sau NAT: không relay, không mở port công khai, mã hoá đầu-cuối.Peerova is a direct P2P tunnel + SDK for any TCP/UDP protocol. Clients reach your service behind NAT directly: no relay, no public open ports, end-to-end encrypted.

Bắt đầu nhanh (5 phút)Quickstart (5 minutes)

  1. Tải peerova cho máy chạy dịch vụ và máy client (Tải về).Download peerova on the machine running your service and on the client (Download).
  2. Chẩn đoán mạng cả hai máy:Diagnose the network on both machines:
    peerova doctor
  3. Tạo khoá định danh server (một lần, giữ bí mật):Create the server identity key (once, keep it secret):
    peerova keygen            # writes server.key
  4. Chạy server với license và các dịch vụ muốn expose:Run the server with your license and the services to expose:
    peerova server --port 47000 --license PVA-XXXXX-XXXXX-XXXXX-XXXXX --expose tcp:443
    # TICKET pvt_....   <- give it to authorized clients
  5. Phía client:On the client:
    peerova client pvt_.... --forward tcp:8443=443
    # now open https://127.0.0.1:8443
Không có license? Bỏ --license để chạy dev mode miễn phí: 1 server, 3 kết nối đồng thời.No license? Omit --license for free dev mode: 1 server, 3 concurrent connections.

Web app / API (dev & staging)Web app / API (dev & staging)

Chia sẻ localhost/staging mà không qua tunnel relay: HTTPS đi đầu-cuối, không subdomain công khai.Share localhost/staging without a relay tunnel: HTTPS stays end-to-end, no public subdomain.

peerova server --license $PEEROVA_LICENSE --private --expose tcp:3000 --expose tcp:443
peerova client pvt_... --forward tcp:3000 --forward tcp:8443=443
curl http://127.0.0.1:3000/api/health

SSH / RDP cho văn phòng (không cần thiết bị VPN)SSH / RDP for offices (no VPN appliance)

# backend/admin machine: access signing key (keeps access.key, prints pvak_...)
peerova keygen --access --key access.key
# office server: only accept tokens signed by that key
peerova server --license $PEEROVA_LICENSE --access-key pvak_... \
  --expose tcp:22 --expose tcp:3389 --expose udp:3389 --audit-log /var/log/peerova/audit.jsonl
# issue an 8-hour SSH-only token for alice
peerova token issue --access-key access.key --ports tcp:22 --ttl 8h --sub alice
# alice
peerova client pvt_... --access-token pva1.... --forward tcp:2222=22
ssh -p 2222 alice@127.0.0.1

Database cho team từ xaDatabases for remote teams

peerova server --license $PEEROVA_LICENSE --access-key pvak_... --expose tcp:5432 --expose tcp:6379
peerova client pvt_... --access-token pva1.... --forward tcp:5432 --forward tcp:6379
psql -h 127.0.0.1 -U app mydb

IoT / thiết bị sau CGNAT (router 4G, camera)IoT / devices behind CGNAT (4G routers, cameras)

# on the device (ARM build): RTSP + web UI
peerova server --license $PEEROVA_LICENSE --expose tcp:554 --expose tcp:80
# operator
peerova client pvt_... --forward tcp:8554=554 --forward tcp:8080=80
ffplay rtsp://127.0.0.1:8554/stream

Sau CGNAT: Peerova ưu tiên IPv6 (đa số mạng 4G VN có), sau đó hole punch qua supernode.Behind CGNAT Peerova prefers IPv6 (most VN mobile networks have it), then hole punching via supernodes.

Game server

peerova server --license $PEEROVA_LICENSE --expose udp:7777 --expose tcp:25565
peerova client pvt_... --forward udp:7777 --forward tcp:25565

Hoặc nhúng SDK để không cần chạy CLI riêng — xem SDK.Or embed the SDK instead of running the CLI — see SDK.

Tham chiếu CLICLI reference

Chạy peerova <lệnh> --help để xem đầy đủ cho phiên bản bạn đang dùng.Run peerova <command> --help for the exact options of your version.

LệnhCommandCờFlagMô tảDescription
peerova doctorChẩn đoán mạng: IPv6, UPnP, NAT-PMP, CGNAT, double NAT.Network diagnosis: IPv6, UPnP, NAT-PMP, CGNAT, double NAT.
peerova keygen[--key server.key]Tạo danh tính server (file pvk_…); ticket cố định theo key.Create the server identity (file pvk_…); the ticket stays stable for that key.
peerova keygen --access[--key access.key]Tạo khoá cấp quyền doanh nghiệp (giữ ở backend/SSO); in public key pvak_… cho --access-key.Create the enterprise access-signing key (keep it in your backend/SSO); prints the public key pvak_… for --access-key.
peerova token issue--access-key access.key --sub alice --ports tcp:443,udp:10000-10100 --ttl 8hPhát token truy cập pva1.…: ký, có hạn, giới hạn port, gắn danh tính.Mint an access token pva1.…: signed, expiring, port-scoped, bound to an identity.
peerova server[--config peerova.json] [--port 47000] [--key server.key]Chạy server. Mọi cờ đều đặt được trong file cấu hình.Run a server. Every flag can live in the config file.
--expose PROTO:PORT[-PORT][=HOST:PORT]Dịch vụ cho phép truy cập; lặp lại; có dải. PROTO: tcp http https ws wss ssh rdp grpc (TCP) · udp quic game (UDP). UDP tới 64 KB.Services clients may reach; repeatable; ranges. PROTO: tcp http https ws wss ssh rdp grpc (TCP) · udp quic game (UDP). UDP up to 64 KB.
--license PVA-…License key (hoặc PEEROVA_LICENSE); bỏ trống = dev mode (1 server, 3 kết nối).License key (or PEEROVA_LICENSE); omit for dev mode (1 server, 3 connections).
--private · --no-map · --no-tcp · --max-ccu N · --ticket-file FILETicket không chứa IP · tắt UPnP/NAT-PMP · tắt TCP fallback · giới hạn kết nối · ghi ticket ra file.Ticket without IPs · disable UPnP/NAT-PMP · disable TCP fallback · cap connections · write the ticket to a file.
--token SECRET | --access-key PUB [--revoked revoked.txt]Mã tham gia dùng chung, hoặc chỉ nhận token ký bởi pvak_… (kèm danh sách thu hồi).Shared join secret, or accept only tokens signed by pvak_… (with a revocation list).
--audit-log audit.jsonlMỗi kết nối một dòng JSON cho SIEM.One JSON line per connection for your SIEM.
--supernode HOST:PORT · --supernode-mode · --no-auto-supernodeSupernode thủ công · chạy như supernode · không tự lấy danh sách supernode.Pin supernodes · act as a supernode · do not fetch the supernode list.
--rdv | --rendezvous URLWebsite làm điểm hẹn → không cần VPS/supernode/relay.Use the website as rendezvous → no VPS/supernode/relay.
--app PRJ --share "Tên dịch vụ" [--public] [--max N] [--mode M] [--region VN] [--tag T]Công bố dịch vụ chia sẻ, nhận mã kết nối 6 ký tự (bí danh: --lobby) (xem Mã kết nối).Announce a service/room and get a 6-char connect code (see Connect codes).
--metrics 127.0.0.1:9184Endpoint Prometheus (xem Metrics).Prometheus endpoint (see Metrics).
peerova client<TICKET|@file|CODE> --forward PROTO:LOCAL[-LOCAL][=REMOTE]Mở 127.0.0.1:LOCAL và tunnel tới port REMOTE đã expose; nhận ticket, file ticket hoặc mã 6 ký tự.Listen on 127.0.0.1:LOCAL and tunnel to the exposed REMOTE port; accepts a ticket, a ticket file or a 6-char code.
[--bind IP] [--access-token TOKEN | --token SECRET] [--reconnect] [--tcp] [--site URL]Địa chỉ bind · token truy cập · tự kết nối lại · ép TCP · website khác mặc định.Bind address · access token · auto-reconnect · force TCP · non-default website.
peerova ping<TICKET|@file> [--count 50] [--interval-ms 100] [--bench-mb 8] [--tcp]Đo RTT, jitter, mất gói và thông lượng.Measure RTT, jitter, loss and throughput.
peerova stdioserver ['<json>'] | client <TICKET> ['<json>']SDK cho mọi ngôn ngữ qua JSON lines stdin/stdout (sidecar).SDK for any language via JSON lines on stdin/stdout (sidecar).
peerova ticket merge<T1> <T2>…Gộp ticket nhiều máy cùng server.key → client tự failover.Merge tickets of several machines sharing server.key → clients fail over automatically.
peerova lease-info<LEASE> [--authority-pubkey B64]Giải mã và kiểm tra một lease pvl1.….Decode and verify a pvl1.… lease.

File cấu hìnhConfig file

peerova server --config peerova.json — mọi cờ đều có khoá tương ứng. Phù hợp khi chạy như service.peerova server --config peerova.json — every flag has a matching key. Ideal when running as a service.

{
  "port": 47000,
  "key_file": "/etc/peerova/server.key",
  "license": "PVA-XXXXX-XXXXX-XXXXX-XXXXX",
  "private": true,
  "expose": ["tcp:443", "tcp:22", "udp:10000-10100"],
  "access_key": "pvak_...",
  "audit_log": "/var/log/peerova/audit.jsonl",
  "tcp_fallback": true,
  "supernodes": []
}

Giao thứcProtocols

Peerova tunnel TCP stream và UDP datagram, nên mọi giao thức phía trên chạy nguyên vẹn. HTTPS/TLS không bao giờ bị giải mã.Peerova tunnels TCP streams and UDP datagrams, so every protocol on top runs unchanged. HTTPS/TLS is never decrypted.

Giao thứcProtocolTransportHỗ trợSupportedGhi chúNotes
TCP (any app)TCP✓Mọi ứng dụng TCP: --expose tcp:PORTAny TCP app: --expose tcp:PORT
UDP (any app)UDP✓Datagram tới 64 KB nhờ phân mảnh trong tunnelDatagrams up to 64 KB via in-tunnel fragmentation
HTTP/1.1 · HTTP/2TCP✓Không cần reverse proxy, Host header giữ nguyênNo reverse proxy, Host header untouched
HTTPS / TLSTCP✓Đầu-cuối: Peerova không giải mã, chứng chỉ của bạn giữ nguyênEnd-to-end: never decrypted, your certificate stays
WebSocket / WSSTCP✓Kết nối dài, upgrade bình thườngLong-lived, normal upgrade
gRPCTCP (HTTP/2)✓Streaming hai chiềuBidirectional streaming
QUIC / HTTP/3UDP✓Forward UDP 443Forward UDP 443
SSH · SFTPTCP✓--expose tcp:22--expose tcp:22
RDP · VNCTCP (+UDP)✓RDP: expose cả tcp:3389 và udp:3389 để mượt hơnRDP: expose both tcp:3389 and udp:3389 for smoother sessions
MySQL · Postgres · Redis · MongoDBTCP✓Giữ TLS của DB nếu có; không cần mở port DB ra InternetKeep DB TLS if used; never expose the DB port publicly
MQTTTCP✓1883 / 8883 (TLS)1883 / 8883 (TLS)
DNSUDP + TCP✓Expose cả udp:53 và tcp:53Expose both udp:53 and tcp:53
VoIP · SIP · RTPUDP✓Dải port RTP: --expose udp:10000-10100RTP port range: --expose udp:10000-10100
FTP (passive)TCP◐Expose tcp:21 + dải passive (vd. tcp:30000-30100) và cấu hình server FTP dùng đúng dải đóExpose tcp:21 + the passive range (e.g. tcp:30000-30100) and pin the FTP server to it
Game UDPUDP✓Gói game, voice chat; CCU giới hạn theo góiGame packets, voice; CCU per plan
ICMP · raw IP (ping, L3 VPN)—✗Chưa hỗ trợ; chế độ VPN L3 nằm trong roadmapNot yet; an L3 VPN mode is on the roadmap

Ticket

Ticket pvt_… là chuỗi bạn trao cho client được phép. Nó chứa khoá công khai Ed25519 của server và gợi ý tìm đường (supernode), không chứa IP thật của server. Client dùng ticket để xác thực đúng server (chống giả mạo) trước khi trao đổi khoá Noise.A ticket pvt_… is what you hand to authorized clients. It carries the server's Ed25519 public key and rendezvous hints (supernodes) — not the server's real IP. Clients use it to authenticate the right server (no impersonation) before the Noise handshake.

Không cần VPS: website làm điểm hẹnNo VPS needed: the website is the rendezvous

Bạn không cần thuê VPS, supernode hay relay. Server Peerova hỏi website mỗi ~2 giây (POST /api/v1/rdv/poll) để công bố địa chỉ; client trình ticket rồi hỏi website (POST /api/v1/rdv/connect) để lấy địa chỉ của server. Hai bên cùng nhận địa chỉ của nhau và đục NAT trực tiếp.You do not need a VPS, a supernode or a relay. A Peerova server asks the website every ~2 s (POST /api/v1/rdv/poll) to announce its addresses; a client holding the ticket asks the website (POST /api/v1/rdv/connect) for the server's addresses. Both sides learn each other's addresses and punch through NAT directly.

  • Dữ liệu không bao giờ đi qua website. Website chỉ trao đổi địa chỉ (IP công khai nhìn thấy, port, địa chỉ LAN/IPv6) lúc bắt đầu kết nối; sau đó mọi gói đi thẳng peer ↔ peer, mã hoá đầu-cuối.Data never passes through the website. It only exchanges addresses (observed public IP, port, LAN/IPv6 addresses) when a connection starts; afterwards every packet goes peer ↔ peer, end-to-end encrypted.
  • Thông tin hẹn tự hết hạn sau 30 giây; mỗi yêu cầu của client chỉ được giao cho server một lần. Ai có ticket thì tra được địa chỉ server — cùng mức tin cậy với chính ticket.Rendezvous entries expire after 30 seconds; each client request is delivered to the server once. Anyone holding the ticket can look up the server address — the same trust level as the ticket itself.
  • Giới hạn: nếu cả hai bên đều sau NAT đối xứng (symmetric) cấp port ngẫu nhiên và không có IPv6, vẫn không kết nối được — điểm hẹn không thay được relay. Bật IPv6 hoặc UPnP ở phía server để chắc chắn.Limit: if both sides are behind random-port symmetric NATs without IPv6, they still cannot connect — a rendezvous is not a relay. Enable IPv6 or UPnP on the server side to be safe.

Supernode

Mọi peerova server reachable cũng là supernode: làm STUN (cho biết địa chỉ public) và giới thiệu hai peer cho nhau để hole punch. Supernode không chuyển dữ liệu của bạn. Có thể chỉ định thủ công bằng --supernode IP:PORT hoặc "supernodes":[] trong config SDK.Every reachable peerova server is also a supernode: it acts as STUN (tells peers their public address) and introduces two peers for hole punching. Supernodes never carry your data. Set them manually with --supernode IP:PORT or "supernodes":[] in the SDK config.

Dark server

Server không mở cổng nào trên router và bỏ qua im lặng mọi gói chưa xác thực: không trả lời, không lộ phiên bản, không lộ dịch vụ. Chỉ client có ticket hợp lệ và được phép mới nhận được địa chỉ để kết nối.The server opens no router ports and silently drops every unauthenticated packet: no reply, no version banner, no service fingerprint. Only authorized clients holding a valid ticket receive the address to connect to.

Giới hạn trung thực: khi đã kết nối trực tiếp, client được phép biết IP server. Peerova không thể hấp thụ DDoS dung lượng lớn từ một client được phép như relay/scrubbing.Honest limit: once connected directly, an authorized client knows the server IP. Peerova cannot absorb a volumetric DDoS from an authorized client the way a scrubbing relay can.

Chống crack: thực thi ở phía mạngAnti-crack: enforced by the network

Lease có thể mang thêm spk — khoá công khai tĩnh của server (contract v2). Core kiểm tra spk trùng khoá của chính nó; supernode chỉ nhận đăng ký kèm lease do authority ký (chữ ký + hạn + spk). Vì vậy bản build bị crack/không có license không dùng được mạng supernode, dù sửa được binary.Leases may carry spk — the server's static public key (contract v2). The core checks spk equals its own key; supernodes only accept registrations that carry an authority-signed lease (signature + expiry + spk). Cracked or unlicensed builds therefore cannot use the supernode network, even if the binary is patched.

  • Server có thể tự đăng ký làm supernode khi xin lease ("supernode":"ip:port"). Danh sách công khai: GET /api/v1/supernodes — tối đa 32 địa chỉ hoạt động trong 30 phút từ license trả phí còn hạn.Servers can offer themselves as supernodes when requesting a lease ("supernode":"ip:port"). Public list: GET /api/v1/supernodes — up to 32 addresses active in the last 30 minutes from valid paid licenses.
  • Supernode không bao giờ chuyển dữ liệu người dùng — chỉ phản chiếu địa chỉ và giới thiệu peer.Supernodes never carry user data — they only reflect addresses and introduce peers.
  • Người dùng có license không bao giờ bị bóp băng thông hay giới hạn tốc độ. Việc thực thi nằm ở phía mạng, không ở trải nghiệm của bạn.Licensed users are never throttled. Enforcement happens on the network side, never in your users' experience.

Phương thức kết nốiConnection methods

#Phương thứcMethodKhi nào thành côngWhen it works
1ipv6Cả hai có IPv6 global (đa số nhà mạng VN và 4G).Both sides have global IPv6 (most VN ISPs and 4G).
2mappedRouter server bật UPnP-IGD/NAT-PMP và IP WAN là public (không CGNAT).Server router has UPnP-IGD/NAT-PMP and a public WAN IP (no CGNAT).
3punchedHole punch UDP qua supernode giới thiệu.UDP hole punching introduced by a supernode.
4lanCùng mạng LAN.Same LAN.
5join codeKhông gì hoạt động: client in mã pvj_, dán vào console server.Nothing else works: the client prints a pvj_ code, paste it into the server console.

Lease & thời gian ân hạnLeases & grace period

Server đổi license key lấy một lease ký Ed25519 (pvl1.…) từ máy chủ license. Core kiểm tra lease offline: chữ ký hợp lệ, mid khớp machine id, chưa quá exp.The server trades its license key for an Ed25519-signed lease (pvl1.…) from the license authority. The core verifies it offline: valid signature, mid equals the machine id, not past exp.

  • Lease hạn 7 ngày; core gia hạn mỗi 6 giờ.Leases last 7 days; the core renews every 6 hours.
  • Mất mạng tới máy chủ license: tiếp tục chạy tới khi lease hết hạn (tối đa 7 ngày).License server unreachable: keep running until the lease expires (up to 7 days).
  • Số server = số machine id khác nhau trong 8 ngày gần nhất.Server count = distinct machine ids seen in the last 8 days.

Bảo mật EnterpriseEnterprise security

  • E2E Noise IKE2E Noise IK — X25519 + ChaCha20-Poly1305; ticket ghim public key server nên không giả mạo được.X25519 + ChaCha20-Poly1305; the ticket pins the server public key, so impersonation fails.
  • Dark serverDark server — Không cổng nào trả lời máy quét; gói chưa xác thực bị bỏ im lặng.No port answers scanners; unauthenticated packets are silently dropped.
  • Token truy cập ký, ngắn hạn, theo portSigned, short-lived, per-port access tokens — peerova token issue --access-key access.key --ports tcp:443 --ttl 8h --sub alice. Phát token từ backend SSO/IdP của bạn.peerova token issue --access-key access.key --ports tcp:443 --ttl 8h --sub alice. Mint them from your own SSO/IdP backend.
  • Allow-list & thu hồi khoá clientClient key allow-list & revocation — Chỉ khoá client được duyệt mới vào; thu hồi tức thì.Only approved client keys get in; revoke instantly.
  • Audit log JSONJSON audit log — Mỗi kết nối: ai, khi nào, dịch vụ nào, bao nhiêu byte — đẩy thẳng vào SIEM.Every connection: who, when, which service, bytes — straight into your SIEM.
  • Chạy như serviceRuns as a service — systemd / Windows service, cấu hình bằng peerova.json.systemd / Windows service with a peerova.json config file.
  • Tự host máy chủ licenseSelf-hosted license authority — Gói Enterprise: chạy authority trên hạ tầng của bạn (Node/VPS).Enterprise plan: run the authority on your own infrastructure (Node/VPS).
  • Dữ liệu không qua nhà cung cấpData never transits vendor servers — Phù hợp yêu cầu tuân thủ và lưu trú dữ liệu.Fits compliance and data-residency requirements.

Token truy cập (theo người, theo port, có hạn)Access tokens (per user, per port, expiring)

Server chạy với --access-key chỉ chấp nhận token ký bởi khoá access.key tương ứng. Token mang sub (danh tính), danh sách port được phép và thời hạn. Tích hợp SSO/IdP: backend của bạn xác thực người dùng (OIDC/SAML…) rồi gọi peerova token issue (hoặc ký cùng định dạng) để cấp token ngắn hạn.A server started with --access-key only accepts tokens signed by the matching access.key. Tokens carry a sub (identity), allowed ports and an expiry. SSO/IdP integration: your backend authenticates the user (OIDC/SAML…) and calls peerova token issue (or signs the same format) to hand out short-lived tokens.

peerova token issue --access-key access.key --ports tcp:443,udp:10000-10100 --ttl 8h --sub alice@corp.vn
# -> pva1.eyJ...   (give to the client: --access-token pva1....)

Thu hồi: token hết hạn tự động; để chặn ngay, xoay --access-key hoặc đưa khoá client vào danh sách thu hồi trong file cấu hình.Revocation: tokens expire on their own; to cut access immediately rotate the --access-key or add the client key to the revocation list in the config file.

Audit log

--audit-log audit.jsonl: mỗi dòng là một sự kiện JSON, đẩy được vào SIEM (Elastic, Splunk, Loki…). Ví dụ (trường có thể mở rộng):--audit-log audit.jsonl: one JSON event per line, ready for your SIEM (Elastic, Splunk, Loki…). Example (fields may be extended):

{"ts":"2026-11-01T09:12:44Z","event":"connect","sub":"alice@corp.vn","client_key":"k7Q…","service":"tcp:22","method":"ipv6","remote":"[2001:db8::5]:51123"}
{"ts":"2026-11-01T10:40:02Z","event":"disconnect","sub":"alice@corp.vn","service":"tcp:22","bytes_in":1834221,"bytes_out":99812,"duration_s":5238}

Chạy như serviceRun as a service

Linux (systemd) — /etc/systemd/system/peerova.service

[Unit]
Description=peerova server
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/peerova server --config /etc/peerova/peerova.json
Restart=always
User=peerova
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/log/peerova

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now Peerova

Windows

sc.exe create peerova binPath= "C:\peerova\peerova.exe server --config C:\peerova\peerova.json" start= auto
sc.exe start peerova

Lưu trú dữ liệu & tự host authorityData residency & self-hosted authority

Dữ liệu ứng dụng không bao giờ đi qua máy chủ của chúng tôi. Thứ duy nhất server gửi lên là yêu cầu lease (key, machine id) và telemetry tổng hợp. Gói Enterprise có thể tự host toàn bộ máy chủ license (Node ≥ 20 trên VPS của bạn) — khi đó không có gì rời hạ tầng của bạn.Application data never transits our servers. The only things a server sends us are lease requests (key, machine id) and aggregate telemetry. Enterprise can self-host the whole license authority (Node ≥ 20 on your VPS) — then nothing leaves your infrastructure.

Giới hạn trung thực: không relay → hai bên đều symmetric NAT cấp port ngẫu nhiên sẽ không kết nối được; client được phép biết IP server; TCP fallback bị head-of-line blocking trên đường mất gói; ICMP/raw IP chưa được tunnel (chế độ VPN L3 trong roadmap).Honest limits: no relay → two random-port symmetric NATs cannot connect; authorized clients learn the server IP; the TCP fallback suffers head-of-line blocking on lossy links; ICMP/raw IP is not tunneled yet (L3 VPN mode on the roadmap).

Cài đặt licenseLicense setup

  1. Đăng ký — key dùng thử 14 ngày hiện một lần duy nhất; hãy lưu lại. Mất key thì bấm “Tạo key mới” (key cũ mất hiệu lực).Sign up — your 14-day trial key is shown once; store it. Lost it? Click “Regenerate key” (the old key stops working).
  2. CLI: --license PVA-…. SDK: trường "license" trong config JSON. Nên đọc từ biến môi trường, đừng commit key vào git.CLI: --license PVA-…. SDK: the "license" field of the config JSON. Read it from an environment variable; never commit keys.
  3. Đổi máy: vào dashboard → License → “Thu hồi” máy cũ để giải phóng slot.Changing hardware: dashboard → License → “Revoke” the old machine to free its slot.

Lỗi leaseLease errors

errorÝ nghĩaMeaning
invalid_keyKey sai hoặc đã được tạo lại.Wrong key, or it was regenerated.
expiredLicense hết hạn — gia hạn trong dashboard.License expired — renew in the dashboard.
revokedLicense hoặc máy này đã bị thu hồi.The license or this machine was revoked.
server_limitVượt số server của gói (máy khác nhau trong 8 ngày).More distinct machines (last 8 days) than the plan allows.

Tự host máy chủ license (Enterprise)Self-hosting the authority (Enterprise)

Toàn bộ web + license chạy được trên VPS bằng Node (server/node-server.mjs). Khoá công khai lấy tại GET /api/v1/pubkey.The whole web + license service runs on a VPS with Node (server/node-server.mjs). The public key is at GET /api/v1/pubkey.

Mã kết nối & dịch vụ chia sẻConnect codes & shared services

Server có thể công bố một dịch vụ chia sẻ lên website và nhận mã kết nối 6 ký tự (vd. K7Q2XD). Người nhận chỉ cần mã thay cho ticket dài. Website chỉ lưu metadata công khai; dữ liệu vẫn đi thẳng P2P. Mã hết hạn 45 giây sau heartbeat cuối (server gửi mỗi ≤ 15 giây).A server can announce a service / room to the website and get a 6-character connect code (e.g. K7Q2XD). Recipients use the code instead of a long ticket. The website only stores public metadata; data still flows peer-to-peer. Codes expire 45 s after the last heartbeat (sent every ≤ 15 s).

Cờ serverServer flagÝ nghĩaMeaning
--app prj_…App ID công khai (ID dự án trong dashboard).Public app ID (the project ID in the dashboard).
--share "Tên dịch vụ"Tên dịch vụ chia sẻ (≤ 64 ký tự); bật mã kết nối. Bí danh cũ --lobby vẫn được chấp nhận.Shared service name (≤ 64 chars); enables connect codes. The old alias --lobby is still accepted.
--publicHiện trong danh sách dịch vụ công khai /connect?app=… (không lộ ticket).List it in the public directory /connect?app=… (ticket never shown).
--max NSố kết nối tối đa hiển thị (0 = không giới hạn hiển thị).Maximum connections shown (0 = unlimited).
--mode M · --region VN · --tag TPhân loại để lọc: vd. web, api, ssh, db, game; khu vực; tối đa 8 tag.Categories for filtering: e.g. web, api, ssh, db, game; region; up to 8 tags.

Ví dụ theo use caseExamples by use case

# Demo web app / API (HTTPS end-to-end) for a client
peerova server --app prj_xxx --share "Demo web" --expose https:443
#   -> connect code K7Q2XD
peerova client K7Q2XD --forward tcp:8443=443          # open https://localhost:8443

# SSH / RDP for staff (combine with --access-key for per-person tokens)
peerova server --app prj_xxx --share "Văn phòng HCM" --mode ssh --expose ssh:22 --expose rdp:3389
peerova client Q4M8ZP --forward tcp:2222=22 --forward tcp:3389

# Database for a remote team
peerova server --app prj_xxx --share "Postgres staging" --mode db --expose tcp:5432
peerova client H2W9CK --forward tcp:5432

# Game server in the public directory
peerova server --app prj_xxx --share "Server game VN" --public --max 16 --mode game --region VN --expose udp:7777
peerova client K7Q2XD --forward udp:7777

SDK

Cấu hình server (C ABI JSON, mọi binding; khoá share, bí danh lobby):Server config (C ABI JSON, every binding; key share, alias lobby):

{"port":47000,"license":"PVA-...","app":"prj_xxx",
 "share":{"name":"Demo API","public":true,"max":50,"mode":"api","region":"VN"}}

Lấy mã bằng peerova_room_code() (Python: srv.room_code); client có thể truyền mã thay cho ticket vào peerova_client_connect. Ngôn ngữ không có FFI dùng sidecar peerova stdio.Read the code with peerova_room_code() (Python: srv.room_code); clients may pass the code instead of a ticket to peerova_client_connect. Languages without FFI use the peerova stdio sidecar.

HTTP API

  • POST /api/v1/lobby/upsert · POST /api/v1/lobby/close — do server gọi— called by the server
  • GET /api/v1/lobby/resolve?code=K7Q2XD → ticket (giới hạn 60 lần/phút/IP)(60/min per IP)
  • GET /api/v1/lobby/list?app=prj_x&mode=&region=&q= · GET /api/v1/lobby/stats?app=prj_x — cho trang danh sách / menu ứng dụng— for directories and in-app menus

Trang nhập mã kết nối & danh sách dịch vụ công khai →Connect-code page & public service directory →

Metrics (Prometheus)Metrics (Prometheus)

peerova server --license $PEEROVA_LICENSE --expose tcp:443 --metrics 127.0.0.1:9184
curl http://127.0.0.1:9184/metrics
# HELP peerova_ccu Connected peers.
# TYPE peerova_ccu gauge
peerova_ccu 12
peerova_max_ccu 200
# TYPE peerova_connects_total counter
peerova_connects_total{path="ipv6"} 31
peerova_connects_total{path="punched"} 18
# TYPE peerova_rejected_total counter
peerova_rejected_total 1
# TYPE peerova_dropped_unauthenticated_total counter
peerova_dropped_unauthenticated_total 4096
# TYPE peerova_failures_total counter
peerova_failures_total 2
peerova_supernode 0

Bind vào 127.0.0.1 (hoặc mạng nội bộ) rồi cho Prometheus/Grafana Agent scrape. Bộ đếm byte (peerova_bytes_*) xuất hiện ở các phiên bản có hỗ trợ — kiểm tra output của bản bạn dùng.Bind to 127.0.0.1 (or an internal network) and let Prometheus / Grafana Agent scrape it. Byte counters (peerova_bytes_*) appear in versions that support them — check your build's output.

SDK — C ABI

Mọi binding gọi cùng một C ABI (peerova.h). Có 4 cách tích hợp: native FFI (mặc định, trong process), JNI (Java/Kotlin/Android), sidecar peerova stdio (JSON lines, cho ngôn ngữ không có FFI), hoặc crate Rust trực tiếp.Every binding wraps the same C ABI (peerova.h). Four integration styles: native FFI (default, in-process), JNI (Java/Kotlin/Android), the peerova stdio sidecar (JSON lines, for languages without FFI), or the Rust crate directly.

#include "peerova.h"   // libpeerova.so · peerova.dll · libpeerova.dylib (or the static lib)

enum { PEEROVA_EVENT_CONNECTED = 1, PEEROVA_EVENT_DISCONNECTED = 2,
       PEEROVA_EVENT_MESSAGE = 3, PEEROVA_EVENT_CONNECT_FAILED = 4 };
typedef struct { int32_t type; uint32_t peer; uint8_t channel; uint8_t reliable;
                 const uint8_t* data; uint32_t len; } peerova_event;

peerova_node* peerova_server_start(const char* config_json);   // blocks until the ticket is ready (≤ ~3 s)
peerova_node* peerova_client_connect(const char* ticket_or_code, const char* config_json);
int32_t  peerova_ticket(peerova_node*, char* buf, int32_t buf_len);      // returns size incl. NUL
int32_t  peerova_room_code(peerova_node*, char* buf, int32_t buf_len);   // 6-char code, 0 if none
int32_t  peerova_send(peerova_node*, uint32_t peer, uint8_t channel,
                      const uint8_t* data, uint32_t len, int32_t reliable); // unreliable max 1180 B
int32_t  peerova_poll(peerova_node*, peerova_event* out);                 // 1 = event, 0 = none
int32_t  peerova_poll_wait(peerova_node*, peerova_event* out, uint32_t timeout_ms);
void     peerova_disconnect(peerova_node*, uint32_t peer);
uint32_t peerova_peer_count(peerova_node*);
void     peerova_free(peerova_node*);
const char* peerova_last_error(void);
const char* peerova_version(void);

Server config JSON: port, key_file, license, private, token, max_ccu, upnp, tcp_fallback, supernodes, rendezvous, app, share. Client config: token, timeout_ms, supernodes, force_tcp. Thư viện được tìm theo PEEROVA_LIB nếu đặt.Server config JSON: port, key_file, license, private, token, max_ccu, upnp, tcp_fallback, supernodes, rendezvous, app, share. Client config: token, timeout_ms, supernodes, force_tcp. Bindings honour PEEROVA_LIB to locate the library.

24 nền tảng24 platforms

TESTED = test round-trip đã chạy PASS trên máy build (Linux x86_64); compile-checked = biên dịch được nhưng chưa chạy trong engine/thiết bị thật; UNTESTED = chưa có toolchain để chạy.TESTED = round-trip test passed on the build machine (Linux x86_64); compile-checked = builds but not yet run in the real engine/device; UNTESTED = toolchain not available yet.

Ngôn ngữ / engineLanguage / engineCơ chếMechanismTrạng tháiStatus
C / C++headerchạy đượcruns
Python 3.8+ctypesTESTEDTESTED
C# (.NET Standard 2.1 / .NET 6+)P/InvokeTESTEDTESTED
Unity 2021.3+ (com.peerova.sdk)P/Invoke + PeerovaBehaviourcompile-checkedcompile-checked
Godot 4.2+ .NET (addons/peerova)P/Invoke + PeerovaNodecompile-checkedcompile-checked
Unreal Engine 5plugin, UPeerovaSubsystemcore C++ TESTED, UE chưa chạycore C++ TESTED, UE not run
Java 8+JNITESTEDTESTED
Kotlin (JVM)JNITESTEDTESTED
Android (NDK arm64/armv7/x86_64)JNIcompile-checkedcompile-checked
Go 1.20+ (github.com/peerova/peerova-go)cgoTESTEDTESTED
Rust (crate peerova)nativeTESTEDTESTED
Node.js ≥ 18sidecar stdioTESTEDTESTED
Electron (main / utilityProcess)sidecar stdioUNTESTEDUNTESTED
Deno ≥ 1.38FFI (Deno.dlopen)UNTESTEDUNTESTED
Bun ≥ 1.0FFI (bun:ffi) / sidecarUNTESTEDUNTESTED
Dart 3dart:ffiTESTEDTESTED
Flutter (Android / iOS / desktop)dart:ffiUNTESTEDUNTESTED
Swift 5.7+ (iOS / macOS / Linux)C module CPeerovaUNTESTEDUNTESTED
Ruby 3.0+FiddleUNTESTEDUNTESTED
PHP 8.1+ (ext/ffi)FFITESTEDTESTED
PHP 8.1+ (no ext)sidecar stdioTESTEDTESTED
LuaJIT 2.1 (LÖVE, OpenResty…)ffi.cdefTESTEDTESTED
Lua 5.1–5.4sidecar stdioTESTEDTESTED
Any language (shell, Erlang, Perl…)sidecar stdio (JSON lines)TESTEDTESTED

C# / .NET

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

using Peerova;   // csharp/Peerova.cs (.NET Standard 2.1 / .NET 6+)

using var srv = Server.Start(new ServerConfig { Port = 47000, License = "PVA-XXXXX-XXXXX-XXXXX-XXXXX" });
Console.WriteLine("ticket: " + srv.Ticket);

while (true)
{
    if (srv.Poll(out Event ev, 100))
    {
        if (ev.Type == EventType.Connected) Console.WriteLine($"peer {ev.Peer} connected");
        if (ev.Type == EventType.Message)   srv.Send(ev.Peer, ev.Data, channel: ev.Channel, reliable: true); // echo
    }
}

Unity

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

Chép com.peerova.sdk vào Packages/ (hoặc Package Manager → Add package from disk), đặt native lib vào Plugins/.Copy com.peerova.sdk into Packages/ (or Package Manager → Add package from disk) and put the native libs into Plugins/.

using UnityEngine;
using Peerova.Unity;   // UPM package com.peerova.sdk (C# binding of the C ABI)

public class NetHost : MonoBehaviour
{
    void Start()
    {
        var net = gameObject.AddComponent<PeerovaBehaviour>();
        net.OnHostStarted.AddListener(ticket => Debug.Log("ticket: " + ticket));
        net.OnMessage.AddListener((peer, ch, data, reliable) =>
            Debug.Log(System.Text.Encoding.UTF8.GetString(data)));
        net.Host();            // or net.Join(ticketOrConnectCode)
    }
}
// Note: write Peerova.Event / Peerova.EventType in full — UnityEngine has types with the same names.

Godot 4

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

Chép addons/peerova vào project (.NET), native lib vào addons/peerova/bin/<os>/, bật plugin, thêm node PeerovaNode.Copy addons/peerova into a .NET project, native libs into addons/peerova/bin/<os>/, enable the plugin and add a PeerovaNode.

# addons/peerova (Godot 4.2+ .NET project) — add a PeerovaNode to the scene
@onready var net = $PeerovaNode

func _ready():
    net.connect("Connected", func(peer): net.SendText(peer, "hi", 0, true))
    net.connect("Message", func(peer, ch, data, reliable): print(data.get_string_from_utf8()))
    net.Join(ticket_or_connect_code)   # or net.Host()

Unreal / C / C++

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

Plugin unreal/Peerova với UPeerovaSubsystem; hoặc gọi trực tiếp C ABI:The unreal/Peerova plugin with UPeerovaSubsystem; or call the C ABI directly:

#include "peerova.h"   /* libpeerova.so · peerova.dll · libpeerova.dylib */
#include <stdio.h>

int main(void) {
    peerova_node* n = peerova_server_start("{\"port\":47000,\"license\":\"PVA-XXXXX-XXXXX-XXXXX-XXXXX\"}");
    if (!n) { fprintf(stderr, "%s\n", peerova_last_error()); return 1; }
    char ticket[1024];
    peerova_ticket(n, ticket, sizeof ticket);
    printf("peerova %s ticket: %s\n", peerova_version(), ticket);

    peerova_event ev;
    for (;;) {
        if (peerova_poll_wait(n, &ev, 100) == 1 && ev.type == PEEROVA_EVENT_MESSAGE)
            peerova_send(n, ev.peer, ev.channel, ev.data, ev.len, 1 /* reliable */);
    }
    peerova_free(n);
}

Python

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

import os, peerova   # ctypes binding; library via PEEROVA_LIB if needed

srv = peerova.Server(port=47000, license=os.environ.get("PEEROVA_LICENSE", "PVA-XXXXX-XXXXX-XXXXX-XXXXX"),
                     app="prj_xxx", share={"name": "Demo API", "public": True, "max": 50})
print("ticket:", srv.ticket, "connect code:", srv.room_code)

for ev in srv.events(timeout=1.0):
    if ev.type == peerova.CONNECTED:
        print("peer", ev.peer, "connected")
    elif ev.type == peerova.MESSAGE:
        srv.send(ev.peer, ev.data, channel=ev.channel, reliable=True)   # echo

Java / Kotlin / Android

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

java/build.sh tạo peerova.jar, libpeerova_jni; Android build JNI bằng NDK cho từng ABI và cần quyền INTERNET.java/build.sh builds peerova.jar and libpeerova_jni; on Android build the JNI lib with the NDK per ABI and add the INTERNET permission.

// java/ (JNI): peerova.jar + libpeerova_jni + libpeerova
try (Peerova.Server srv = Peerova.Server.start("{\"port\":47000}");
     Peerova.Client cli = Peerova.Client.connect(srv.ticket())) {
    Peerova.Event ev = cli.poll(10000);          // CONNECTED
    cli.send(ev.peer, "hello", 0, true);
    Peerova.Event m = srv.poll(5000);            // CONNECTED, then MESSAGE
}

Go, Node, Deno, Bun, Dart, Swift, Ruby, PHP, Lua…Go, Node, Deno, Bun, Dart, Swift, Ruby, PHP, Lua…

preview API SDK đang ở bản preview và có thể thay đổi trước bản 1.0. CLI đã ổn định.The SDK API is a preview and may change before 1.0. The CLI is stable.

// go get github.com/peerova/peerova-go   (cgo, links libpeerova)
srv, _ := peerova.StartServer(`{"port":47000}`)
defer srv.Close()
cli, _ := peerova.Connect(srv.Ticket(), "")
ev, _ := cli.PollWait(10 * time.Second)        // Connected
cli.Send(ev.Peer, []byte("hello"), 0, true)

Node/Electron/PHP không ext/Lua thuần/shell dùng sidecar: spawn peerova stdio server|client và trao đổi JSON lines — không cần native module.Node/Electron, PHP without ext/ffi, plain Lua and shells use the sidecar: spawn peerova stdio server|client and exchange JSON lines — no native module needed.

import { Peerova } from "peerova";          // bindings/nodejs (sidecar)
const srv = await Peerova.server({ port: 47000 });
srv.on("message", (peer, data) => console.log(data.toString()));
const cli = await Peerova.client(srv.ticket);
cli.on("connected", (peer) => cli.send(peer, "hello", { channel: 0, reliable: true }));

So sánh: mở port / NAT truyền thống vs relay vs PeerovaCompare: port forwarding vs relay vs Peerova

Bản gốc: docs/COMPARISON.md. Có ô cảnh báo — chúng tôi nói rõ giới hạn.Source: docs/COMPARISON.md. Some cells are caveats — we state the limits plainly.

Mở port truyền thốngPort forwardingRelayPeerova
Cần cấu hình routerRouter configurationCó, phải forward tayYes, manual forwardingKhôngNoKhông: tự dùng UPnP/NAT-PMP, IPv6 hoặc hole punchNo: automatic UPnP/NAT-PMP, IPv6 or hole punching
Port lộ ra InternetPort exposed to the InternetMở công khai, ai cũng quét thấyPublic; any scanner sees itKhông (server nằm sau relay)No (server sits behind the relay)Dark: không trả lời gói thiếu ticket, quét port không thấy gìDark: no reply without a ticket; scans see nothing
Chạy sau CGNAT (4G, nhiều gói cáp quang)Works behind CGNAT (4G, many fibre plans)KhôngNoCóYesĐược nếu có IPv6 hoặc phía server reachable; không được nếu cả hai bên đều symmetric NAT/CGNAT và không có IPv6Yes with IPv6 or a reachable server side; no if both sides are symmetric NAT/CGNAT without IPv6
Tỷ lệ kết nốiConnection success~100% nếu mở port được~100% if you can open a port~100%~100%Ước tính 85–95%; gần 100% với dedicated server bạn kiểm soát mạngEstimated 85–95%; near 100% for dedicated servers whose network you control
Độ trễLatencyThấp nhất (đường thẳng)Lowest (direct path)+10–80 ms (đi vòng qua relay)+10–80 ms (detour via relay)Thấp nhất (đường thẳng)Lowest (direct path)
Chi phí vận hànhRunning cost00Theo CCU / băng thôngPer CCU / bandwidth≈ 0 băng thông; chỉ thuê license≈ 0 bandwidth; license only
Băng thông tối đaMax bandwidthBăng thông thậtYour real bandwidthBị giới hạn bởi relayCapped by the relayBăng thông thật (982 Mbit/s đo trên loopback)Your real bandwidth (982 Mbit/s on loopback)
Mã hoáEncryptionTuỳ game (thường không)Up to the game (often none)Thường chỉ tới relayOften only up to the relayE2E Noise IK (X25519 / ChaCha20-Poly1305)E2E Noise IK (X25519 / ChaCha20-Poly1305)
Chống MITM / giả serverMITM / fake server protectionKhôngNoPhụ thuộc relayDepends on the relayCó: ticket chứa public key serverYes: the ticket pins the server public key
Ẩn IP serverServer IP hiddenLộ hoàn toànFully exposedẨn sau relayHidden behind the relayMột phần: ticket riêng không chứa IP; IP chỉ lộ cho client đã có ticket và đã xác thựcPartly: private ticket has no IP; only authenticated ticket holders learn it
Chống DDoS dung lượng lớnVolumetric DDoSKhôngNoRelay hấp thụAbsorbed by the relayKhông hấp thụ được nếu kẻ tấn công đã được cấp quyền và biết IP; người lạ không thấy serverCannot absorb it from an authorized client who knows the IP; strangers cannot see the server
Đổi mạng giữa trận (Wi-Fi → 4G)Network change mid-match (Wi-Fi → 4G)RớtDropsTuỳVariesRoaming: tự cập nhật địa chỉ theo gói đã xác thựcRoaming: address updated from authenticated packets
Phụ thuộc bên thứ 3Third-party dependencyKhôngNoCó (dịch vụ relay)Yes (relay service)Không (web chỉ cấp license; offline vẫn chạy 7 ngày)No (web only issues licenses; runs 7 days offline)
Giao thứcProtocolsMọiAnyThường chỉ SDK riêngOften the vendor SDK onlyMọi: TCP (HTTP/HTTPS/WS/SSH…) + UDP (game, QUIC, voice) + SDKAny: TCP (HTTP/HTTPS/WS/SSH…) + UDP (game, QUIC, voice) + SDK

Hạn chế thật của P2P / NAT traversalReal limits of P2P / NAT traversal

Hạn chếLimitNguyên nhânCausePeerova xử lýHow Peerova handles it
Symmetric NAT ↔ symmetric NAT không punch đượcSymmetric ↔ symmetric NAT cannot be punchedMỗi đích có port ngoài khác nhau, không đoán đượcEach destination gets an unpredictable external portƯu tiên IPv6; phía server bật UPnP/NAT-PMP hoặc mở 1 port UDP (dark nên an toàn); port prediction ở roadmapPrefer IPv6; enable UPnP/NAT-PMP on the server or open one UDP port (safe, it is dark); port prediction on the roadmap
CGNAT (100.64.0.0/10)CGNAT (100.64.0.0/10)Nhà mạng NAT thêm một lớp, UPnP vô dụngThe ISP adds a NAT layer; UPnP is uselessIPv6, hoặc xin IP public (peerova doctor tự phát hiện)IPv6, or ask for a public IP (peerova doctor detects it)
Firewall doanh nghiệp chặn UDPCorporate firewall blocks UDPChính sách mạngNetwork policyChưa xử lý được: không relay, không TCP fallback — giới hạn của lựa chọn "0 relay"Not handled: no relay, no TCP fallback — the cost of "zero relay"
IP server lộ cho client hợp lệServer IP visible to valid clientsKết nối trực tiếp thì gói phải mang IP thậtDirect packets must carry the real IPPrivate ticket, token/allow-list, giới hạn CCU, rate-limit handshakePrivate ticket, token/allow-list, CCU limits, handshake rate limiting
Kết nối ban đầu chậm hơnSlower initial connectThu thập địa chỉ → punch → bắt tayGather addresses → punch → handshakeThường vài chục ms tới 1–2 s, sau đó như kết nối thẳngTypically tens of ms to 1–2 s, then like a direct link
Cần điểm hẹn trao đổi địa chỉNeeds a rendezvousNAT ẩn địa chỉ thậtNAT hides real addressesSupernode (server khác của hệ thống), ticket, join code thủ côngSupernodes (other Peerova servers), tickets, manual join code

Vì sao dedicated server hợp với PeerovaWhy dedicated servers fit Peerova

Hole punching chỉ thất bại khi cả hai đầu đều ở NAT khó. Khi bạn kiểm soát mạng phía server (IPv6, UPnP hoặc mở 1 port UDP — vẫn dark) thì server reachable và mọi client kết nối được.Hole punching only fails when both ends are behind hard NATs. When you control the server network (IPv6, UPnP, or one UDP port — still dark) the server is reachable and every client connects.

Số đo đã có (lab/mô phỏng): ping +12 ms khi link 95% tải; UDP 982 Mbit/s và TCP fallback 851 Mbit/s trên loopback; dữ liệu đúng 100% khi mất 30% gói. Tỷ lệ kết nối 85–95% là ước tính (Ford, Srisuresh & Kegel, USENIX 2005: ~82% NAT hỗ trợ UDP hole punching) — chưa phải số đo Internet thật.Measured so far (lab/simulation): +12 ms ping at 95% link use; UDP 982 Mbit/s and TCP fallback 851 Mbit/s on loopback; 100% data integrity at 30% loss. The 85–95% success rate is an estimate (Ford, Srisuresh & Kegel, USENIX 2005: ~82% of NATs support UDP hole punching) — not a real-Internet measurement yet.

Xử lý sự cốTroubleshooting

CGNAT

Nếu IP WAN trên router khác IP public (thường là 100.64.x.x), bạn đang sau CGNAT: UPnP vô dụng. Giải pháp tốt nhất là bật IPv6; nếu không, hole punch vẫn thường thành công khi phía kia dễ tính.If your router's WAN IP differs from your public IP (often 100.64.x.x), you are behind CGNAT: UPnP will not help. The best fix is enabling IPv6; otherwise hole punching often still works when the other side is friendly.

Double NAT

Modem nhà mạng + router riêng = hai lớp NAT. Chuyển modem sang chế độ bridge, hoặc bật UPnP ở cả hai, hoặc đặt router riêng vào DMZ của modem.ISP modem + your own router = two NAT layers. Put the modem in bridge mode, enable UPnP on both, or put your router in the modem's DMZ.

Bật IPv6Enable IPv6

Vào trang quản trị router → WAN/IPv6 → bật IPv6 (SLAAC/DHCPv6, prefix delegation). Viettel, VNPT, FPT đều hỗ trợ. Kiểm tra lại bằng peerova doctor.Router admin → WAN/IPv6 → enable IPv6 (SLAAC/DHCPv6, prefix delegation). Most ISPs support it. Re-check with peerova doctor.

UPnP

Bật UPnP-IGD hoặc NAT-PMP trong router. Peerova chỉ xin mapping tạm thời và tự gỡ khi tắt.Enable UPnP-IGD or NAT-PMP on the router. Peerova only requests a temporary mapping and removes it on exit.

Firewall hệ điều hànhOS firewall

Cho phép peerova nhận UDP trên Windows Defender Firewall / ufw. Không cần mở cổng trên router.Allow peerova to receive UDP in Windows Defender Firewall / ufw. No router port needed.

Vẫn không được?Still stuck?

Dùng mã join thủ công (pvj_…) và gửi kết quả peerova doctor của cả hai máy cho chúng tôi.Use the manual join code (pvj_…) and send us the peerova doctor output from both machines.