BaoTa Panel Deployment
This guide shows the current, source-aligned way to run Epusdt with BaoTa (宝塔).
Prefer Docker or pure CLI? See Docker Deployment or Manual Deployment.
Prerequisites
Prepare the following before deployment:
- A Linux server with BaoTa installed
- Nginx installed in BaoTa
- Supervisor installed in BaoTa
- A public domain pointed to the server
- A valid TronGrid API key
- A built
epusdtbinary or official release package
If you plan to compile the binary yourself before uploading it to BaoTa, use a Go toolchain compatible with the current source repository's src/go.mod (at review time: Go 1.25.0).
Database choices supported by current source:
- SQLite: simplest option, no external database service required
- MySQL: optional
- PostgreSQL: optional
WARNING
Current source does not require Redis, and current startup does not require manually importing SQL tables in the normal case. The app auto-creates its tables on first start.
Some older upstream BaoTa/manual tutorials still mention Redis and hand-imported SQL. For this docs set, prefer the current source tree and .env.example over those historical guides.
Deployment layout
Typical BaoTa setup:
- BaoTa Nginx terminates HTTP/HTTPS
- Epusdt listens on
127.0.0.1:8000 - BaoTa Supervisor keeps the process running
- SQLite or your chosen SQL database stores data
runtime_root_pathandlog_save_pathmay be absolute or relative- In the current
.env.example, they default to absolute paths/runtimeand/logs - If you prefer to keep everything under the site directory, change them to relative paths such as
runtimeandlogs
Example app directory:
/www/wwwroot/pay.example.com/
├── epusdt
├── .env
├── static/
└── runtime/Step 1: Create the site in BaoTa
In Website:
- Click Add Site
- Bind your domain, for example
pay.example.com - A static/default site type is fine because Epusdt serves its own HTTP app
- If you plan to use MySQL, create the database here as well
Step 2: Upload the application
Upload the Epusdt binary or release package into the site directory, for example:
/www/wwwroot/pay.example.com/Make it executable:
chmod +x /www/wwwroot/pay.example.com/epusdtTIP
Keep .env, epusdt, and the static/ directory together. The server reads .env from its working directory and serves static assets from ./static by default.
Step 3: Prepare .env
Create or edit .env in the same directory as the binary:
app_name=epusdt
app_uri=https://pay.example.com
http_listen=:8000
static_path=/static
runtime_root_path=runtime
log_save_path=logs
# supported values: sqlite, mysql, postgres
db_type=sqlite
# SQLite primary database file
# leave empty to use the current source default: runtime/store.sqlite
sqlite_database_filename=
runtime_sqlite_filename=epusdt-runtime.db
# MySQL example
# db_type=mysql
# mysql_host=127.0.0.1
# mysql_port=3306
# mysql_user=epusdt
# mysql_passwd=change-this-db-password
# mysql_database=epusdt
# PostgreSQL example
# db_type=postgres
# postgres_host=127.0.0.1
# postgres_port=5432
# postgres_user=epusdt
# postgres_passwd=change-this-db-password
# postgres_database=epusdt
api_auth_token=replace-with-a-long-random-secret
tron_grid_api_key=replace-with-your-trongrid-api-key
order_expiration_time=10
# Optional Telegram bot
tg_bot_token=
tg_proxy=
tg_manage=Minimum production values to review carefully:
app_uri: your final public HTTPS URLapi_auth_token: merchant API signing secrettron_grid_api_key: required for TRON/TRC20 monitoringdb_typeand matching DB fields if not using SQLite
Step 4: Database notes
SQLite
For a single-server deployment, SQLite is the easiest choice.
- No manual schema import is normally needed
- Epusdt auto-migrates its tables on startup
- Primary data and runtime locks use SQLite files
- If you leave
sqlite_database_filenameempty, the main database defaults toruntime/store.sqlite runtime_sqlite_filenamedefaults toepusdt-runtime.dbunder the resolved runtime directory- Make sure the chosen database and runtime paths are writable by the service user
MySQL / PostgreSQL
If you prefer an external database:
- Set
db_type=mysqlordb_type=postgres - Fill in the matching connection fields
- Ensure the database server is reachable from the BaoTa host
- The app still keeps its runtime lock store in SQLite via
runtime_sqlite_filename
Step 5: Configure reverse proxy
Epusdt serves HTTP itself, so BaoTa should proxy to it.
In the site settings, create a reverse proxy to:
http://127.0.0.1:8000Recommended proxy behavior:
- Enable HTTPS on the public site
- Keep
app_uriexactly equal to the public URL - Do not mount Epusdt under a subdirectory unless your reverse proxy also rewrites paths carefully
If BaoTa lets you edit the generated Nginx config, preserve standard forwarding headers such as:
HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto
Step 6: Add a Supervisor process
Create a new BaoTa Supervisor task.
Working directory:
/www/wwwroot/pay.example.com/Start command:
/www/wwwroot/pay.example.com/epusdt http startWARNING
Current source uses the http start subcommand. Do not configure Supervisor to run only ./epusdt unless your packaged binary explicitly documents that behavior.
Step 7: Start and verify
After saving the Supervisor task:
- Start the process
- Open
https://pay.example.com/ - Confirm the site responds normally
- Check Supervisor or application logs if startup fails
Useful checks:
- Root page should respond at
/ - Checkout pages are served under
/pay/... - API endpoints are served under
/payments/...
Recommended BaoTa hardening
- Enable automatic HTTPS certificate renewal
- Block direct web access to
.env - Keep the app directory writable only for the service user
- Back up your database files or external SQL database regularly
- Watch logs for callback failures and chain polling errors
Troubleshooting
502 Bad Gateway
Usually means Nginx cannot reach Epusdt.
Check:
- Supervisor process is running
- Start command is
epusdt http start http_listenmatches the reverse proxy target- The process can read
.envfrom its working directory
Startup fails after changing paths
Check whether these paths are valid and writable:
runtime_root_pathlog_save_pathsqlite_database_filenameif you set it explicitlyruntime_sqlite_filename
Path rules in current source:
runtime_root_path: relative paths are resolved from the.envdirectorylog_save_path: relative paths are resolved fromruntime_root_pathsqlite_database_filename: if relative, it is resolved from the.envdirectoryruntime_sqlite_filename: if relative, it is resolved underruntime_root_path
Orders are created but payments never confirm
Check:
- Wallet addresses were added correctly
- The network is TRON / TRC20 USDT as expected by your integration
tron_grid_api_keyis valid- The server can reach external TRON/HTTP APIs
Callback keeps failing
Check:
- Your
notify_urlis publicly reachable - The merchant callback endpoint returns HTTP
200with bodyok - TLS and reverse proxy rules are not blocking outbound callback retries
