English | العربية | 简体中文 | 繁體中文 | Français | Русский | Español | 日本語
Vocat is an open-source web control panel and engineering toolkit for Quectel EC20/EC25-class and China Mobile ML307 series cellular modems. It combines modem discovery, live radio status, AT and USSD terminals, SMS, WiFi Calling, eSIM management, network selection, proxy routing, notifications, audit logs, and release automation in one self-contained service.
The backend is written in Go, the interface is built with React and TypeScript, and the production frontend is embedded into the Go binary. A single executable contains the web application and uses SQLite for persistent state.
| Area | What Vocat provides |
|---|---|
| Device management | Automatic serial/USB discovery, multiple modem support, friendly device names, live overview updates, module restart, flight mode, and USB networking mode controls. |
| Radio and network | Registration status, operator, signal metrics, RSRP/RSRQ/SINR, network mode, band, channel, operator scanning, automatic or manual network selection, and LTE cell querying and single-cell lock/unlock (EARFCN/PCI). |
| AT and USSD | Interactive AT terminal, command history, raw modem responses, USSD start/continue/cancel flows, and clear modem error reporting. |
| SMS | Direct cellular and IMS SMS transmission, inbound synchronization, multipart handling, delivery reports, conversation history, unread state, timestamps, and per-message delivery status. |
| WiFi Calling | IKEv2/ePDG tunnel setup, EAP-AKA authentication, IMS registration, IMS SMS, reconnect controls, status diagnostics, and per-device routing. |
| eSIM and eUICC | eUICC discovery, EID and production information, certificate metadata, multi-eUICC inventory, installed profile listing, enable/disable/switch operations, download, rename, and delete operations when supported by the card. |
| Card policy | ICCID-based WiFi Calling and flight-mode behavior with immediate policy application. |
| Proxy routing | Upstream SOCKS routing, device bindings, country rules, TCP reachability checks, and UDP Associate checks for WiFi Calling data paths. |
| Notifications | New inbound SMS forwarding through Telegram, Bark, email, Pushplus, and signed webhooks. Each SMS is delivered as an individual notification. |
| Telegram bot | Device status, installed-profile listing and switching, WiFi Calling controls, and SMS sending. Sensitive actions require administrator confirmation. |
| Operations | Password and SSO authentication (Pocket ID, GitHub, Generic OAuth2), CSRF protection, access policies, audit events, live logs, log retention, health checks, responsive layout, dark mode, and English/Chinese application UI. |
| Distribution | Static Linux binaries, systemd installation script, self-update with SHA-256 verification, Docker image, GHCR publishing, and GitHub Actions release builds. |
Vocat targets Qualcomm-based Quectel and China Mobile ML307 series modules that expose compatible AT, QMI, serial, and USB networking interfaces, including:
- Quectel EC20
- Quectel EC25
- Quectel EG25 family
- Compatible EG600 and related modules
- China Mobile ML307 series (e.g. ML307A-E5, various OEMs)
Available features depend on the module firmware, USB composition, SIM/eSIM capabilities, host drivers, radio network, and carrier configuration.
As root (including OpenWrt/Kwrt, where sudo is normally absent):
curl -fsSL https://raw.githubusercontent.com/MengMengCode/VoCat/master/scripts/install.sh | bashFrom a normal user on a distribution with sudo:
curl -fsSL https://raw.githubusercontent.com/MengMengCode/VoCat/master/scripts/install.sh | sudo bashCheck the host's VoWiFi/XFRM prerequisites without installing VoCat:
curl -fsSL https://raw.githubusercontent.com/MengMengCode/VoCat/master/scripts/install.sh | bash -s -- --check-envInstall a specific version:
curl -fsSL https://raw.githubusercontent.com/MengMengCode/VoCat/master/scripts/install.sh -o install.sh
sudo bash install.sh 0.0.2VoWiFi IMS requires Linux XFRM/IPsec. On OpenWrt/Kwrt the installer attempts
to install matching ip-full, kmod-ipsec, kmod-ipsec4/6,
kmod-crypto-authenc, AES-CBC and SHA1 packages from the firmware's own feed.
If matching kernel modules are unavailable, use a firmware that includes them;
never force-install kmods built for a different kernel.
If your kernel cannot provide XFRM/IPsec and you only need non-VoWiFi features
such as cellular SMS or data, install with --skip-vowifi-check:
curl -fsSL https://raw.githubusercontent.com/MengMengCode/VoCat/master/scripts/install.sh -o install.sh
sudo bash install.sh --skip-vowifi-checkThe installer:
- detects
amd64,386,arm64,aarch64, orarmv7; - downloads the matching GitHub Release binary;
- verifies it against
SHA256SUMS; - installs Vocat under
/opt/vocat; - creates a hardened systemd service with the hardware and network access required by Vocat;
- stores runtime configuration in
/etc/vocat/env; - generates a random initial administrator password on first installation.
After installation, open:
http://<server-address>:7575
Download the matching binary and SHA256SUMS from GitHub Releases:
| Platform | Release file |
|---|---|
| Linux x86-64 | vocat-linux-amd64 |
| Linux x86 32-bit | vocat-linux-386 |
| Linux ARM64 | vocat-linux-arm64 |
| Linux AArch64 | vocat-linux-aarch64 |
| Linux ARMv7 | vocat-linux-armv7 |
Verify and install it:
sha256sum -c SHA256SUMS --ignore-missing
sudo install -d -m 0755 /opt/vocat/bin /opt/vocat/data
sudo install -m 0755 vocat-linux-amd64 /opt/vocat/bin/vocat
read -rsp "Admin password: " VOCAT_BOOTSTRAP_PASSWORD; echo
printf '%s\n' "$VOCAT_BOOTSTRAP_PASSWORD" | sudo /opt/vocat/bin/vocat bootstrap-admin
unset VOCAT_BOOTSTRAP_PASSWORD
sudo env \
VOCAT_DATABASE_PATH=/opt/vocat/data/vocat.db \
/opt/vocat/bin/vocat serveThis manual command runs Vocat in the foreground. Use vocat serve so the
process starts the server directly; running vocat without arguments as root
on a TTY opens the interactive management menu instead. Use the one-click
installer when a managed systemd service and automatic restart are required.
For a Linux host that must discover every attached supported Quectel modem and continue seeing USB hot-plug events, run Vocat in hardware-access mode:
docker pull ghcr.io/mengmengcode/vocat:latest
read -rsp "Admin password: " VOCAT_BOOTSTRAP_PASSWORD; echo
printf '%s\n' "$VOCAT_BOOTSTRAP_PASSWORD" | docker run --rm -i \
--user 0:0 \
-v vocat-data:/opt/vocat/data \
--entrypoint /opt/vocat/bin/vocat \
ghcr.io/mengmengcode/vocat:latest bootstrap-admin
unset VOCAT_BOOTSTRAP_PASSWORD
docker run -d \
--name vocat \
--restart unless-stopped \
--network host \
--privileged \
--user 0:0 \
-v vocat-data:/opt/vocat/data \
-v /dev:/dev \
-v /sys:/sys:ro \
ghcr.io/mengmengcode/vocat:latestOpen http://<server-address>:7575 after the container starts. Host networking
is required so QMI network interfaces remain visible to Vocat, while privileged
device access is required for serial ports, QMI control nodes, TUN interfaces,
network configuration, and devices added after the container starts. The
/dev bind mount makes new ttyUSB*, ttyACM*, cdc-wdm*, and MHI
wwan* nodes visible without recreating the container.
This mode intentionally gives Vocat broad access to the host's devices and
network stack. Use it only on a trusted Linux host. The automatic discovery
identifies supported Quectel USB modems (USB vendor ID 2c7c) and China Mobile ML307 series modules by product string, and PCIe/MHI
modems exposed through the Linux WWAN subsystem; it does not identify arbitrary
modem layouts. Mapping only individual nodes with --device, such as
/dev/ttyUSB2, /dev/cdc-wdm0, or /dev/wwan0qmi0, limits the container to
those fixed nodes and does not provide complete multi-device or hot-plug discovery.
On OpenWrt hosts, the fw4 input chain drops new connections from interfaces it
does not manage, including Vocat's per-session VoWiFi TUN. Vocat therefore
inserts narrow vocat-ims-* accept rules (P-CSCF to the negotiated inner
address) with the nft bundled in the image. Without them IMS registration and
outgoing SMS still work, but incoming SMS and calls are rejected. If the bundled
nft cannot read the host ruleset, Vocat logs nft could not inspect the OpenWrt fw4 input chain; point VOCAT_NFT at the host's own nft instead:
cat > /opt/vocat-host-nft <<'EOF'
#!/bin/sh
exec /host/lib/ld-musl-$(uname -m).so.1 --library-path /host/usr/lib:/host/lib /host/usr/sbin/nft "$@"
EOF
chmod 755 /opt/vocat-host-nft
# Add to the docker run command above:
# -v /usr:/host/usr:ro -v /lib:/host/lib:ro \
# -v /opt/vocat-host-nft:/usr/local/bin/host-nft:ro \
# -e VOCAT_NFT=/usr/local/bin/host-nftThe GHCR image is published for linux/amd64 and linux/arm64.
Tip
NAS / QNAP Container Station Deployment Note:
On NAS operating systems like QNAP QTS / QuTS hero (Container Station), custom non-root administrator accounts and volume isolation mechanisms may cause Docker named volumes (e.g. -v vocat-data:/opt/vocat/data) to resolve to different isolated paths between the one-off bootstrap-admin initialization and the daemon service container, leading to "Incorrect password" errors during Web login.
For NAS environments, it is strongly recommended to replace named volumes with a host absolute path bind mount (e.g. -v /share/Container/vocat/data:/opt/vocat/data on QNAP) for both initialization and runtime to guarantee consistent SQLite database persistence.
USB SIM readers use the Linux PC/SC service. The one-click installer installs
and starts pcscd plus the CCID driver automatically on supported package
managers. On Debian/Ubuntu, the equivalent manual setup is
apt install pcscd libccid. If USB sees a CCID reader but PC/SC is unavailable,
VoCat keeps the reader visible in the add-device dialog and reports the missing
service or driver instead of silently hiding it.
VoCat uses qmicli to verify that a QMI control channel is ready and
qmi-proxy to multiplex access to it. Packet-data sessions are managed by the
built-in QMI WDS client instead of qmi-network CID/PDH state files. The
one-click installer installs and verifies the corresponding utilities. For manual deployment,
Debian/Ubuntu uses apt install libqmi-utils; Arch Linux uses
pacman -S libqmi, Alpine uses apk add qmi-utils, and OpenWrt uses
opkg install qmi-utils.
vocat doctor --repair-dji-qmi checks for qmicli before changing any USB
driver binding or asserting DTR. If the utility is unavailable, the command
stops with an installation hint and leaves the current device state untouched.
AT-backed ECM/RNDIS data requires Linux, iproute2 and BusyBox with udhcpc.
VoCat must exclusively manage the modem network interface; disable competing
DHCP clients or network-manager profiles for that interface. VoCat maintains
an IPv4 lease and marked policy routes without changing the system default
route or resolver. This path currently requires IPv4-capable service.
Vocat reads an optional JSON configuration file from VOCAT_CONFIG, then applies VOCAT_* environment variables. Environment variables take precedence.
| Environment variable | Default | Description |
|---|---|---|
VOCAT_ADDR |
0.0.0.0:7575 |
HTTP listen address. |
VOCAT_DATABASE_PATH |
./data/vocat.db |
SQLite database path. |
VOCAT_SESSION_TTL |
24h |
Authentication session lifetime. |
VOCAT_SECURE_COOKIES |
false |
Optional force-Secure override for all entries; HTTP/HTTPS cookies otherwise adapt automatically. |
VOCAT_SHUTDOWN_TIMEOUT |
10s |
Graceful shutdown timeout. |
VOCAT_MAX_REQUEST_BODY_BYTES |
1048576 |
Maximum API request body size. |
VOCAT_MCP_ENABLED |
true |
Serve the MCP endpoint at /mcp for AI agents. Set false to disable it. |
VOCAT_PROBE_UNKNOWN_USB |
false |
Opt in to probing unrecognized USB serial devices with AT commands. Probing changes serial settings and clears input; enable only when those ports are dedicated to modems. Verified modem identities are discovered automatically. JSON key: probe_unknown_usb. |
VOCAT_REPO |
MengMengCode/VoCat |
Trusted GitHub repository used by the self-updater, in owner/name form. |
GITHUB_TOKEN |
empty | Optional GitHub token for private repositories or higher API limits. |
User-supplied Apple carrier bundles can be converted into reviewable,
allow-listed carrier profiles with vocat carrier import-ipcc; see
docs/CARRIER_IPCC_IMPORT.md.
Administrator credentials are stored only in SQLite. Initialize an empty
database once with vocat bootstrap-admin; environment variables and JSON
configuration cannot set or overwrite the administrator username or password.
Do not store Telegram tokens, SMTP passwords, webhook secrets, SIM credentials, or other private data in the repository. Configure them through the application settings or protected environment files.
VoCat supports Pocket ID through OpenID Connect, GitHub.com OAuth Apps, and Generic OAuth2 providers. Select one provider in Settings → Single sign-on (SSO). SSO starts disabled and password login remains available. Sign in with the local administrator first, save a provider, and explicitly bind an external account before enabling SSO. Other external accounts cannot register or become administrators, including accounts sharing the bound account's email address.
- Use an HTTPS origin for VoCat, such as
https://vocat.example.com, and set the HTTPS entry as the public origin. Cookie security is selected automatically for each browser entry;VOCAT_SECURE_COOKIES=trueis only an optional global force-Secure override. In the SSO settings choose Pocket ID. The public origin initially uses the current browser address; edit the visible VoCat public origin field if necessary. The compact callback URL and Copy button appear immediately, so the URL can be copied before creating the OIDC client or saving any credentials:https://vocat.example.com/api/auth/sso/callback. - In Pocket ID create a separate Confidential OIDC client for VoCat. Register the exact callback URL and verify that the intended user or group is allowed to use this client. VoCat and Komari need separate clients and local sessions.
- In VoCat enter Pocket ID's exact public
APP_URLas the Issuer, and enter the Client ID and Client Secret issued for the client created in step 2. The Client ID field includes a reminder of where to find this value. Scopes and PKCE S256 are handled by VoCat. Token authentication is selected from validated Discovery metadata, preferringclient_secret_basicoverclient_secret_post. Save while SSO remains disabled. Origin edits update the displayed callback immediately; they take effect for authorization after saving. - Check the saved configuration; success displays Configuration check passed. Then bind the account. Complete Pocket ID's Passkey login and consent, and confirm the returned binding in VoCat. Configuration checking validates metadata and connectivity; it cannot verify a client secret or user authorization without this login.
- Enable SSO and save. Use a private browser window to verify SSO login, return to the requested page, and the first state-changing request.
The settings page shows the bound account and an unbind action. To change the external account, unbind it first, then bind the intended account and enable SSO again.
The Issuer is matched exactly, including its path and trailing slash. Pocket ID
login uses the verified ID Token's issuer + sub; a UserInfo endpoint or email
claim is not required. Discovery and its authorization, Token and JWKS endpoints
must use the configured Issuer's origin. Deployments using INTERNAL_APP_URL
with a different backend origin are not supported in this release. Keep the
public APP_URL as the Issuer. Existing explicitly
configured authentication methods and scopes are preserved when saving.
For GitHub, create an OAuth App on GitHub.com with the same exact callback URL,
select GitHub, enter its Client ID and Secret, and follow the save, check,
bind, enable sequence above. Endpoints are fixed to GitHub.com; the default
scope is read:user, and PKCE S256 is required. The binding follows the stable
GitHub numeric account ID, so changing a login name does not change the account.
GitHub Enterprise is outside this release's scope.
For Generic OAuth2, supply the authorization, Token, and UserInfo URLs in addition
to the client credentials. Scopes, the top-level user ID field (default id),
Token authentication and PKCE compatibility options are displayed when Generic
OAuth2 is selected.
UserInfo is requested with a Bearer access token. The ID must be a
nonempty string or an integer; large integer IDs retain their exact value.
The default Token authentication is client_secret_post and PKCE is S256.
Disable PKCE only for a provider that lacks PKCE support.
Generic OAuth2 does not perform OIDC ID Token verification.
One saved provider and account binding can serve the configured HTTPS public origin and explicit local/private IP entries over HTTP or HTTPS. Register each complete callback URL (/api/auth/sso/callback) with the identity provider. Authorization and token exchange use the same callback frozen at flow creation; callbacks on a different entry are rejected. HTTP is accepted only for localhost, loopback and literal private IP addresses, not arbitrary public HTTP hosts.
IPv6 callback hosts use the browser's compressed spelling, including hexadecimal IPv4-mapped addresses. Register the callback shown in settings with the identity provider. Existing configurations using an expanded IPv6 spelling are recognized automatically, but the provider must accept the normalized callback URL.
Direct TLS, the configured HTTPS public origin behind a proxy, and trusted X-Forwarded-Proto select Secure cookies automatically. Untrusted forwarded headers are ignored. Proxies must preserve Host. Password sessions use their request transport, the explicit override, and same-authority HTTPS Origin/Referer hints that can only upgrade Cookie protection. These browser hints do not authorize requests, change network access policy, or select callback destinations.
A session persists its Secure-cookie requirement at sign-in and can only upgrade it on later HTTPS requests, including when a missing or stale CSRF cookie must be replaced without scheme hints. Existing sessions keep working after the additive database migration; their previous transport cannot be inferred, so HTTPS users with an existing session should sign in again or make a refresh with a recognized HTTPS signal.
Saving or disabling SSO does not change password-client Cookie behavior. A proxy that removes all browser and transport scheme information must explicitly provide a trusted HTTPS signal. The configured-origin fallback is limited to SSO sign-in and SSO-session CSRF refreshes. Separate LAN HTTP entries remain usable without a process restart or configuration switch; remove a legacy force-Secure override when using both protocols. HTTP credentials travel without transport encryption.
VoCat's existing source-network policy also applies to SSO routes. Configuring SSO does not make an installation publicly accessible. The browser must reach VoCat and the authorization endpoint; the VoCat process must reach Discovery, Token and JWKS/UserInfo endpoints with trusted TLS certificates. Saving the exact Pocket ID HTTPS Issuer or Generic endpoint URLs approves those addresses for HTTPS connections, including RFC1918/IPv6 ULA private addresses. GitHub's fixed endpoints remain restricted to public addresses.
For a Generic provider's internal HTTP service, explicitly enter its full HTTP URL in the Token/UserInfo field. Every DNS candidate and actual connection for these HTTP destinations must be a permitted private address. Pocket ID's Discovery cannot approve another origin; its endpoints must use the configured Issuer's origin. The Issuer, Discovery fetch URL and browser authorization endpoint always require HTTPS. Loopback, link-local, cloud metadata and other special-use destinations remain blocked for IdP connections. Install private CA certificates in the host/container trust store; there is no TLS verification bypass option. The browser's localhost or HTTPS origin for VoCat is independent of these IdP connection permissions.
The supplied Compose deployment uses host networking. Verify DNS, routing and CA
trust from the actual container; do not assume bridge-network service names are
available. Reverse proxies must preserve the configured public origin. VoCat
does not derive callback URLs from forwarded host headers. Root-path deployment
is required. For local Vite development, use one consistent loopback origin,
such as http://127.0.0.1:5173, for the public origin and callback registration;
IdP transport exceptions belong only in test fixtures.
Session and CSRF cookies retain SameSite=Strict; short-lived authorization
cookies use SameSite=Lax for top-level GET callbacks. Saving any SSO
configuration, including disabling it or rotating the secret, revokes all SSO
sessions. Unbinding an account revokes that binding's SSO sessions.
Password sessions and API tokens survive those actions. Changing the local
administrator's password revokes all sessions and API tokens, cancels in-flight
authorizations, and preserves the external binding. The UI requests sign-in
again when a successful operation revokes the current SSO session.
Leave the secret input empty to preserve an existing secret, or enter a new secret to replace it. The settings page does not offer a secret-clearing control. Changing the provider, client ID, Issuer, or Generic identity endpoints/ID field requires a new identity namespace, new credentials, and a new binding. Existing bindings require explicit reset confirmation. To change the bound account, unbind it and then create a new binding. Client secrets are held only on the server in the protected SQLite database; the sensitive-setting flag redacts responses and does not encrypt the database. Third-party tokens are not persisted or returned to the browser.
Signing out ends only the current VoCat session. Disabling an IdP account or
signing out of Pocket ID does not immediately revoke an existing VoCat session;
it expires according to VOCAT_SESSION_TTL, or can be revoked by disabling SSO
or unbinding in VoCat. The public capabilities endpoint is
GET /api/auth/providers. SSO settings and binding APIs require a browser
session and CSRF for writes; Bearer tokens cannot manage them. Configuration
revision conflicts return 409 sso_config_changed; changed identity sources
return 409 sso_rebind_required.
SSO adds SQLite schema version 29. Upgrades preserve the existing administrator,
sessions, API tokens and device data; SSO remains disabled until configured.
Before upgrading, record the old binary or image digest and back up configuration,
CA material and the complete persistent data directory while VoCat is stopped,
or use SQLite's backup API/.backup to obtain a consistent live snapshot. Copying
only a running WAL-mode database file is not a reliable backup.
Disable SSO in the new version to recover from provider problems while keeping
password login and current business data. Returning to a schema-28 binary
requires stopping VoCat and restoring the matching pre-upgrade data and
configuration snapshot. Merely reverting the container image or lowering
PRAGMA user_version cannot downgrade the database. Restore into a separate
directory/volume where possible and retain the newer database for investigation.
Restoring a snapshot loses messages and task changes recorded after that backup.
For Docker, update by pulling the image and recreating the container.
Before a production release, complete the real Pocket ID Passkey/access-policy test and an upgrade/rollback rehearsal for that deployment.
Non-browser clients authenticate against the same /api/... endpoints with
a bearer token instead of the browser's session cookie and CSRF flow:
vocat token create --read-only --ttl 720h ci-runner # prints the token once
curl -H "Authorization: Bearer vcat_..." http://127.0.0.1:7575/api/devicesvocat token list and vocat token revoke <name> manage the inventory.
Tokens act with administrator privileges; a --read-only token may only
issue GET requests (one documented exception: reading an SMS thread marks
it read locally — the rule is "no hardware or network mutations"). Rotating
the administrator password revokes every token. Create tokens after the
first bootstrap-admin. Remote bearer clients also need a network access
policy that admits their source address; the default internal mode only
serves private networks.
By default (VOCAT_MCP_ENABLED=false to disable), the same service
exposes an MCP (Model Context Protocol) endpoint for AI agents at http://<host>:7575/mcp using
the Streamable HTTP transport and bearer-token authentication. Tools cover
device status, SMS threads and guarded sending, eSIM profile listing and
switching, and WiFi Calling status/reconnect; sensitive operations (raw AT,
eSIM download/delete, SIM PIN, network selection, system update) are not
exposed, and tool output never includes IMSI, SIM PIN, or activation codes.
A read-only token receives a tool list without the write tools. SMS sending
follows the same blocked-destination policy and global hourly limit as the
web UI and sends over the cellular AT path (the web UI's IMS-preferred
routing when WiFi Calling is enabled stays web-side, and messages sent
through MCP are not yet written to the web conversation history).
Client configuration (Claude Code as the example):
{
"mcpServers": {
"vocat": {
"type": "http",
"url": "http://192.168.1.10:7575/mcp",
"headers": { "Authorization": "Bearer vcat_..." }
}
}
}See docs/API_MCP_DEVELOPMENT_PLAN.md for the design record.
When Telegram notifications are enabled and both Chat ID and Admin ID are configured, the bot supports:
/status [device]
/esim <device>
/switch <device> <iccid>
/wfc <device> <status|on|off|reconnect>
/sms <device> <number> <message>
/ussd <device> <code>
/ussd_reply <session> <input>
/ussd_cancel <session>
Profile switching and SMS submission use one-time confirmation buttons. The bot does not expose eSIM download, delete, or rename commands.
The web terminal and Telegram share USSD routing. With WiFi Calling enabled, requests use IMS/USSI and return a readiness error until IMS registers, without falling back to cellular AT+CUSD. With WiFi Calling disabled, requests use cellular USSD. Menu replies and cancellation stay bound to the original device and dialog. Cancellation errors are reported and retain the session for retry; an uncertain submission is never automatically resubmitted over another channel.
USSI dialog handling follows 3GPP TS 24.390. A failed BYE retains a cancellation record, but further menu input is blocked once cancellation has started (RFC 3261, section 15.1.1).
Check for a newer GitHub Release:
vocat update --check --repo MengMengCode/VoCatInstall the latest release:
sudo vocat update --repo MengMengCode/VoCatThe updater downloads the binary matching the current Linux architecture, verifies it with the published SHA256SUMS, replaces the executable atomically, and restarts the vocat systemd service when available.
For Docker installations:
docker pull ghcr.io/mengmengcode/vocat:latestRecreate the container after pulling the new image.
Requirements:
- Go 1.25 or newer
- Node.js 20 or newer
- npm
Run the frontend development server:
cd web
npm install
npm run devBuild the embedded frontend and start the backend:
cd web
npm run build
cd ..
go run ./cmd/vocatRun all tests:
go test ./...Build a production binary:
go build -trimpath -ldflags "-s -w" -o vocat ./cmd/vocatPushing a version tag starts two GitHub Actions workflows:
release-binariesbuilds and publishesamd64,386,arm64,aarch64, andarmv7binaries plusSHA256SUMS.dockerbuilds and publishes a multi-architecture image to GitHub Container Registry.
git tag v0.2.0
git push origin v0.2.0cmd/vocat/ Application entry point and CLI
internal/device/ Modem discovery and device control
internal/modem/ AT session and response handling
internal/server/ HTTP API, notifications, and embedded web server
internal/store/ SQLite persistence
internal/update/ GitHub Release self-updater
internal/vowifi/ IKE, EAP-AKA, IMS, and WiFi Calling runtime
scripts/install.sh Linux installer and updater
web/src/ React and TypeScript frontend
.github/workflows/ Binary and Docker release automation
Cellular modem and eSIM operations can affect subscriber service, stored profiles, network registration, and hardware state. Keep backups, review destructive actions carefully, and use the software only in lawful environments where you are permitted to operate the connected hardware and network resources.
Vocat does not bypass carrier authentication, network policy, hardware security, or eSIM trust requirements. Support for an operation means that Vocat can request it from the modem or eUICC; the device, profile, network, or carrier may still reject it.
Issues and pull requests are welcome. Keep changes focused, include tests where practical, avoid committing credentials or subscriber data, and document hardware-specific behavior clearly.
Before submitting a change:
go test ./...
cd web && npm run build- Nodeseek.com — A community dedicated to servers
- Linux.do — An inspiring tech community
- iniwex5 — Style and Functionality Guidelines
| Network | Address |
|---|---|
| USDT-TRON (TRC20) | TWSAkvzVsFc7KqncDLmUfRxpPQbpV5CgTB |
| USDT-BSC (BEP20) | 0xb43031387342ebb1ff536fb9ad6440b9e6377139 |
| USDT-Polygon | 0xb43031387342ebb1ff536fb9ad6440b9e6377139 |
See LICENSE.

