Expose là một ứng dụng tunnel mã nguồn mở được phát triển bởi BeyondCode (tác giả Marcel Pociot), viết hoàn toàn bằng PHP. Công cụ này cho phép bạn chia sẻ môi trường phát triển cục bộ (localhost) của mình với người khác trên internet thông qua một URL công khai, đồng thời hỗ trợ nhận và kiểm tra webhook trong quá trình phát triển ứng dụng.
Nếu bạn đã từng sử dụng ngrok, bạn sẽ nhanh chóng nhận ra Expose cung cấp tập tính năng tương tự nhưng với một ưu điểm quan trọng: toàn bộ lõi là mã nguồn mở, có thể tự host server trên hạ tầng của chính mình và được viết bằng PHP – ngôn ngữ quen thuộc với đại đa số PHP developer, đặc biệt là cộng đồng Laravel.
Kể từ khi ra mắt vào năm 2020, Expose đã thu hút hơn 4.500 sao trên GitHub và trở thành lựa chọn hàng đầu cho PHP developer cần một giải pháp tunnel linh hoạt, có thể kiểm soát hoàn toàn.

Expose hoạt động như thế nào?
Expose tạo một đường hầm (tunnel) giữa URL cục bộ trên máy của bạn và một máy chủ công khai. Tất cả request gửi đến máy chủ công khai sẽ được chuyển tiếp qua tunnel về máy của bạn, và phản hồi được gửi trả lại tự động. Bên dưới lớp vỏ, Expose sử dụng framework ReactPHP để xử lý kết nối bất đồng bộ hiệu năng cao.
Expose bao gồm hai thành phần chính:
- Client (máy khách): Chạy trên máy phát triển cục bộ của bạn, tạo kết nối tunnel đến server.
- Server (máy chủ): Có thể là server quản lý của Expose.dev, hoặc server tự host của chính bạn.
Các tính năng nổi bật của Expose
- Mã nguồn mở và tự host: Toàn bộ mã nguồn của Expose được công bố công khai trên GitHub dưới giấy phép MIT. Bạn có toàn quyền tự host server tunnel trên hạ tầng của mình, đảm bảo dữ liệu luôn nằm trong tầm kiểm soát.
- Dashboard cực đẹp và nhiều tính năng: Ngay sau khi bắt đầu chia sẻ một site, Expose khởi động một dashboard web tại
http://localhost:4040. Dashboard này cho phép:- Xem các HTTP request đến theo thời gian thực
- Xem chi tiết đầy đủ của từng request và response (headers, body, status code, duration)
- Replay bất kỳ request nào mà không cần kích hoạt lại webhook gốc – đặc biệt hữu ích khi test các payment webhook
- Sao chép lệnh
curltương đương của từng request
- Terminal UI: Song song với dashboard web, giao diện dòng lệnh cũng hiển thị các request đến, giúp bạn quan sát nhanh mà không cần mở trình duyệt.
- Mã QR để test trên thiết bị di động: Khi bắt đầu chia sẻ một site, Expose hiển thị mã QR để bạn có thể quét bằng điện thoại hoặc máy tính bảng và truy cập ngay lập tức vào URL công khai.
- Xác thực cơ bản (Basic Authentication): Có thể thêm lớp bảo vệ username/password cho tunnel, hữu ích khi chia sẻ với khách hàng hoặc đội ngũ nội bộ.
- Hỗ trợ subdomain tùy chỉnh: Plan Pro cho phép đặt tên subdomain cố định, giúp bạn không cần cập nhật lại URL mỗi khi kết nối lại.
- Tích hợp Laravel Herd: Nếu bạn đang sử dụng Laravel Herd, Expose đã được tích hợp sẵn, chỉ cần cấu hình token là dùng được ngay.
- Hỗ trợ Docker: Expose cung cấp Docker image chính thức để triển khai server tự host một cách nhanh chóng và nhất quán.
Các phương án sử dụng Expose
Expose có ba hình thức sử dụng chính:
- Free Plan (Managed): Dùng server miễn phí tại trung tâm dữ liệu ở Đức (EU), subdomain ngẫu nhiên, có giới hạn thời gian kết nối. Phù hợp với việc thử nghiệm nhanh hoặc demo tạm thời.
- Expose Pro (Managed): Mạng lưới server toàn cầu, subdomain cố định, custom domain, không giới hạn thời gian, hỗ trợ đội nhóm. Phù hợp với môi trường làm việc chuyên nghiệp hoặc team.
- Self-hosted: Tự host server trên hạ tầng của bạn, toàn quyền kiểm soát dữ liệu, phù hợp với các tổ chức có yêu cầu bảo mật hoặc riêng tư cao.
Yêu cầu hệ thống
Trước khi cài đặt Expose, cần đảm bảo:
- PHP: Phiên bản hiện đại (PHP 8.0 trở lên được khuyến nghị)
- Composer (nếu cài đặt qua Composer)
- Kết nối internet để kết nối đến server Expose hoặc server tự host
Cài đặt Expose Client
Cách 1: Qua PHAR Archive (Khuyến nghị cho máy tính cá nhân)
Đây là phương pháp đơn giản nhất, chỉ cần có PHP trên máy:
# Tải file thực thi
curl https://github.com/exposedev/expose/raw/master/builds/expose -L --output expose
# Cấp quyền thực thi
chmod +x expose
# Chuyển vào thư mục trong PATH để gọi từ bất kỳ đâu
sudo mv expose /usr/local/bin/exposeSau bước này, lệnh expose có thể được gọi từ bất kỳ thư mục nào trong hệ thống.
Cách 2: Qua Composer Global
Nếu bạn đã sử dụng Composer trong quá trình phát triển PHP:
composer global require exposedev/exposeTiếp theo, đảm bảo thư mục bin của Composer global được thêm vào biến môi trường PATH. Thêm dòng sau vào file ~/.bash_profile hoặc ~/.bashrc (Linux/macOS):
export PATH=~/.composer/vendor/bin:$PATHSau đó áp dụng thay đổi:
source ~/.bash_profileCách 3: Laravel Herd
Nếu bạn đang sử dụng Laravel Herd, Expose đã được cài sẵn. Không cần thêm bước nào, chỉ cần cấu hình token là sử dụng được.
Cập nhật Expose lên phiên bản mới nhất
expose self-updateCấu hình xác thực (Authentication Token)
Sau khi cài đặt, bước tiếp theo là cấu hình token xác thực. Truy cập expose.dev/register để tạo tài khoản miễn phí và lấy
token.
Thiết lập token bằng lệnh:
expose token YOUR_TOKEN_HERELệnh này sẽ tự động cập nhật file cấu hình tại ~/.expose/config.php.
Nếu bạn dùng Laravel Herd, có thể cấu hình token trực tiếp trong giao diện cài đặt của Herd mà không cần dùng dòng lệnh.
Chia sẻ site đầu tiên với Expose
Chia sẻ một URL localhost cơ bản
# Chia sẻ ứng dụng chạy trên cổng 3000
expose share http://localhost:3000
# Chia sẻ ứng dụng chạy trên cổng 8000
expose share http://localhost:8000Ngay sau khi chạy, Expose hiển thị URL công khai để chia sẻ, ví dụ: https://random-name.sharedwithexpose.com.
Chia sẻ một local domain
Nếu bạn sử dụng Laravel Valet, Laravel Herd hoặc cấu hình host tùy chỉnh:
expose share my-local-site.dev
# Chia sẻ qua HTTPS cục bộ
expose share https://my-local-site.devChia sẻ với subdomain tùy chỉnh (Pro)
expose share http://localhost:8000 --subdomain=myappLệnh trên sẽ tạo URL cố định dạng myapp.sharedwithexpose.com, rất hữu ích khi phải cấu hình endpoint webhook một lần cho cả dự án.
Chia sẻ với xác thực cơ bản
Để bảo vệ tunnel bằng username và password:
expose share my-site.test --basicAuth="admin:secret"
# Kết hợp với subdomain tùy chỉnh
expose share my-site.test --subdomain=site --basicAuth="admin:secret"Ngoài ra, bạn có thể khai báo thông tin xác thực trong file expose.yml ở thư mục gốc của dự án để không cần truyền tham số mỗi lần chạy:
auth:
username: admin
password: secretSử dụng Dashboard để kiểm tra Request
Sau khi bắt đầu chia sẻ, mở trình duyệt và truy cập:
http://localhost:4040Dashboard hiển thị toàn bộ các HTTP request đến theo thời gian thực. Đối với mỗi request, bạn có thể:
- Xem đầy đủ headers của request và response
- Xem body nội dung
- Xem status code và thời gian xử lý
- Replay request: Gửi lại đúng y request đó mà không cần kích hoạt lại webhook trên
hệ thống ngoài – đặc biệt hữu ích khi debug payment gateway hoặc các hệ thống webhook
phức tạp như Stripe, PayPal, hay các nền tảng thương mại điện tử
Kể từ Expose 3.0, tính năng replay còn cho phép chỉnh sửa nội dung request trước khi gửi lại, giúp việc kiểm thử trở nên linh hoạt hơn nhiều so với các công cụ tương tự.
Tự host Expose Server với Docker
Yêu cầu
- Máy chủ đã cài Docker và Docker Compose
- Tên miền trỏ đến IP máy chủ
- Chứng chỉ SSL (có thể dùng Let’s Encrypt miễn phí)
Tạo cấu trúc thư mục
mkdir expose-server && cd expose-server
mkdir -p databaseTạo file docker-compose.yml
services:
expose:
image: beyondcodegmbh/expose-server:latest
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- 8080:${PORT}
environment:
port: ${PORT}
domain: ${DOMAIN}
username: ${ADMIN_USERNAME}
password: ${ADMIN_PASSWORD}
restart: always
volumes:
- ./database/expose.db:/root/.exposeCấu hình này sẽ:
- Sử dụng Docker image chính thức của Expose server
- Map cổng container ra cổng 8080 trên máy chủ
- Lưu trữ cơ sở dữ liệu SQLite ra ngoài container để dữ liệu không bị mất khi restart
- Tự động khởi động lại nếu container bị lỗi hoặc máy chủ reboot
Tạo file .env
PORT=8080
DOMAIN=yourdomain.com
ADMIN_USERNAME=yourusername
ADMIN_PASSWORD=yourpasswordThay thế yourdomain.com, yourusername và yourpassword bằng thông tin thực tế của
bạn.
Khởi động server
docker compose up -dKiểm tra trạng thái:
docker compose psGiao diện quản trị có thể truy cập tại expose.yourdomain.com sau khi server hoạt động.
Cấu hình Nginx Reverse Proxy (Khuyến nghị)
Để bảo mật kết nối bằng HTTPS và hỗ trợ WebSocket đầy đủ, cấu hình Nginx như sau:
server {
listen 443 ssl;
server_name *.yourdomain.com yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}Lưu ý quan trọng: Vì Expose tạo tunnel trên các subdomain động, Nginx phải được cấu hình với wildcard subdomain (
*.yourdomain.com). Chứng chỉ SSL cũng cần là wildcard certificate tương ứng. Nếu dùng Let’s Encrypt, có thể lấy wildcard cert thông qua DNS challenge với Certbot.
Cấu hình Client kết nối đến Server Tự Host
Sau khi server tự host hoạt động, cần cấu hình client để kết nối vào đó thay vì server mặc định của Expose.
Tạo file cấu hình
expose publishLệnh này tạo file cấu hình tại ~/.expose/config.php.
Chỉnh sửa file cấu hình
Mở file ~/.expose/config.php và thêm thông tin server tự host:
return [
// ... các tùy chọn khác
'servers' => [
'main' => [
'host' => 'sharedwithexpose.com',
'port' => 443,
],
'my-server' => [
'host' => 'yourdomain.com',
'port' => 443, // hoặc 8080 nếu không dùng reverse proxy
],
],
// Đặt server tự host làm mặc định
'default_server' => 'my-server',
// ... các tùy chọn khác
];Thiết lập token cho server tự host
expose token YOUR-AUTH-TOKENChia sẻ site qua server tự host
# Sử dụng server mặc định đã cấu hình
expose share http://localhost:8000
# Hoặc chỉ định rõ tên server
expose share http://localhost:8000 --server=my-serverSử dụng cấu hình riêng cho từng dự án
Đối với các team làm việc trên nhiều dự án khác nhau với cấu hình Expose riêng biệt:
EXPOSE_CONFIG_FILE="/path/to/project-config.php" expose share myapp.testCác lệnh CLI hay dùng
| Lệnh | Mô tả |
|---|---|
expose share http://localhost:3000 | Chia sẻ ứng dụng trên cổng 3000 |
expose share myapp.test | Chia sẻ local domain |
expose share myapp.test --subdomain=demo | Chia sẻ với subdomain tùy chỉnh |
expose share myapp.test --basicAuth="user:pass" | Chia sẻ với xác thực cơ bản |
expose share myapp.test --server=my-server | Chỉ định server cụ thể |
expose token YOUR_TOKEN | Thiết lập token xác thực |
expose publish | Xuất file cấu hình |
expose self-update | Cập nhật lên phiên bản mới nhất |
So sánh Expose với các giải pháp tương tự
| Tính năng | Expose | ngrok | Cloudflare Tunnel |
|---|---|---|---|
| Mã nguồn mở | Có | Không (client đóng) | Không |
| Tự host server | Có | Không | Có (zero trust) |
| Viết bằng PHP | Có | Không | Không |
| Dashboard web | Có | Có | Hạn chế |
| Replay request | Có | Có (plan trả phí) | Không |
| Chỉnh sửa request trước replay | Có (v3.0+) | Không | Không |
| Basic auth | Có | Có | Qua Access policy |
| Docker support | Có | Có | Có |
| Tích hợp Laravel Herd | Có | Không | Không |
| Miễn phí | Có (có giới hạn) | Có (có giới hạn) | Có |
| Giấy phép | MIT | Độc quyền | Độc quyền |
Xử lý một số lỗi thường gặp
Không kết nối được đến server
- Kiểm tra tên miền đã trỏ đúng vào IP máy chủ chưa
- Kiểm tra tường lửa (firewall) trên máy chủ đã mở cổng tương ứng chưa
- Kiểm tra lại thông tin
hostvàporttrong file cấu hình client - Một số mạng nội bộ chặn kết nối WebSocket; thử dùng cổng 443 với SSL
Test kết nối nhanh bằng:
curl -vI https://yourdomain.comLỗi xác thực token
- Kiểm tra token đã được sao chép chính xác chưa
- Chạy lại
expose token YOUR_TOKENđể ghi đè cấu hình cũ - Kiểm tra tùy chọn “Validate Authentication Tokens” trong admin dashboard của server
Xác nhận token đã được lưu đúng bằng cách:
expose token YOUR_TOKEN
cat ~/.expose/config.phpDashboard không hiển thị request
- Đảm bảo đang truy cập đúng
http://localhost:4040(không phải HTTPS) - Kiểm tra cổng 4040 có bị chặn bởi firewall cục bộ không
- Thử khởi động lại
expose sharenếu dashboard bị treo
Lỗi SSL với wildcard certificate
- Xác nhận chứng chỉ SSL đã bao gồm wildcard subdomain (
*.yourdomain.com) - Nếu dùng Let’s Encrypt, sử dụng DNS challenge thay vì HTTP challenge để lấy wildcard cert
- Kiểm tra cấu hình Nginx đã bao gồm cả
*.yourdomain.comtrongserver_name
Câu hỏi thường gặp
Expose có hoàn toàn miễn phí không?
Lõi của Expose là mã nguồn mở và miễn phí. Dịch vụ managed miễn phí có giới hạn thời gian kết nối và sử dụng server EU với subdomain ngẫu nhiên. Nếu cần subdomain cố định, mạng toàn cầu hoặc custom domain, cần nâng lên Expose Pro.
Expose có thể dùng để nhận webhook không?
Có. Đây là một trong những use case chính của Expose. Tính năng replay request trên dashboard giúp việc debug webhook trở nên đơn giản hơn nhiều so với các công cụ khác.
Có thể tự host Expose Server mà không cần Docker không?
Có. Expose server cũng là một ứng dụng PHP và có thể chạy trực tiếp bằng PHP mà không cần Docker, tuy nhiên Docker là phương án được khuyến nghị vì đơn giản hóa việc cài đặt và bảo trì.
Expose có hỗ trợ tunnel TCP không?
Expose hiện tại tập trung chủ yếu vào HTTP/HTTPS tunnel. Hỗ trợ TCP thuần chưa được tích hợp chính thức như ngrok. Nếu cần tunnel TCP, ngrok hoặc frp có thể là lựa chọn phù hợp hơn cho use case đó.
Expose là lựa chọn xuất sắc cho các PHP developer và Laravel developer đang cần một công cụ tunnel linh hoạt, có thể tự host và hoàn toàn có thể kiểm soát. Việc được viết bằng PHP giúp toàn bộ cộng đồng PHP dễ dàng đóng góp, tùy chỉnh và mở rộng công cụ này theo nhu cầu thực tế.
Với khả năng tự host trên Docker, dashboard trực quan, tính năng replay và chỉnh sửa webhook, tích hợp sẵn trong Laravel Herd, và giấy phép MIT cho phép sử dụng tự do, Expose đáp ứng được cả nhu cầu phát triển cá nhân lẫn môi trường nhóm hoặc doanh nghiệp có yêu cầu bảo mật dữ liệu nghiêm ngặt.








