Deployment topology and License
This document describes ApiGo's production deployment structure and License authorization mechanism. Addresses, accounts, and secrets are always injected through environment variables or external configuration files; this document records no real values.
Deployment topology
Component list
| Component | Required | Description |
|---|---|---|
| MySQL 8.4+ | Required | Platform metadata; also stores call logs when ES is not enabled |
| Redis 7+ | Required | Runtime configuration hub, Pub/Sub change notifications, distributed locks, response cache |
| Registry (Nacos 2.3+ or Eureka) | Required for cluster deployment | Service discovery, cluster node count probing; can be omitted for direct single-node connections |
| Elasticsearch 7+ | Optional | Call log search; once enabled, logs are no longer written to MySQL |
| apigo-admin | Required | Admin APIs and configuration distribution |
| apigo-api | Required | API execution engine |
| apigo-gateway | Required | Unified entry point and governance |
| apigo-web | Required | Static assets for the frontend portal |
Startup order
- MySQL, Redis, registry (and the optional Elasticsearch)
apigo-adminapigo-apiapigo-gatewayapigo-web
At startup, the admin loads data sources and writes runtime configuration to Redis; the gateway depends on this data to build routes. If the order is reversed, the gateway may briefly have no routes and self-heals after the next reconciliation, but for first-time deployments you should still start the services in order.
Port conventions
| Service | Default port |
|---|---|
| apigo-admin | 9377 |
| apigo-api | 9366 |
| apigo-gateway | 9600 |
| apigo-web | Nginx 80 (container maps 8080); Vite default 7000 in development mode |
Open APIs all enter through the gateway at 9600; apigo-api is not exposed directly.
Configuration security
The following configurations must be externalized and must not be written into the code repository or documentation:
- Database address, account, password
- Redis address and password
- AI model API key
- SMTP / SMS / Webhook credentials
- License file and private key
We recommend injecting them through environment variables, a configuration center, or a mounted application-*.yml, and restricting file permissions. Data source passwords are stored encrypted with RSA/SM2 inside the platform, but this does not replace access control on configuration files.
License mechanism
Protection scope
apigo-admin, apigo-api, and apigo-gateway all depend on the apigo-license module. All three services validate authorization at startup; if any service fails validation, it cannot start.
Validation pipeline
- Signature verification: verify the signature with the public key built into the release jar (trust anchor) to prevent forgery and tampering; development builds can specify it via
apigo.license.public-key. - Time window: the current time must fall between
notBeforeandnotAfter. - Service whitelist: when
serviceIdsis non-empty, the current service'sspring.application.namemust be in the list, preventing one License from working for all services. - Typed validation: check the MAC or cluster node count according to the license type.
- Clock rollback: compare with the time watermark recorded in the state file; a rollback beyond the tolerance is treated as tampering.
Three license types
| Type | Validation content | Applicable scenarios |
|---|---|---|
SIMPLE | Time window only | Demos, PoC, fully dynamic environments |
STANDARD | Time + server MAC binding | Single machine, physical machine, fixed cluster |
CLUSTER | Time + cluster node count range (no MAC check) | Dynamic container environments such as Kubernetes and Swarm |
For CLUSTER, the node count is max(registry instance count, configured lower bound). The configured value can only declare a lower bound; it cannot lower the actual probed count, preventing bypass of the node limit by changing configuration.
License payload
| Field | Meaning |
|---|---|
licenseId | License ID (UUID) |
licensee | Licensee name |
productCode | Product line code (optional) |
type | SIMPLE / STANDARD / CLUSTER |
algorithm | Signature algorithm: RSA or SM2 |
issueAt / notBefore / notAfter | Issue, effective, and expiry time (epoch seconds) |
macs | Authorized MAC list (STANDARD) |
maxNodes / minNodes | Node count upper / lower limit (CLUSTER) |
serviceIds | Service whitelist (optional) |
Key configuration
| Configuration | Default | Description |
|---|---|---|
apigo.license.enabled | false | Can be disabled only in development builds; enforced once the release package has a built-in trust anchor |
apigo.license.license-file | - | External license file path; supports bare paths, file:, and classpath: |
apigo.license.check-interval | 24h | Scheduled validation period, minimum 1 minute |
apigo.license.clock-skew-tolerance | 24h | Clock rollback tolerance |
apigo.license.state.file | ~/.apigo/license.state | Rollback watermark state file |
apigo.license.state.strict | true | Refuse to run when the state file is unavailable (fail-closed) |
apigo.license.mac.primary-interface | Auto-detected | Primary network interface to validate |
apigo.license.cluster.node-count | 1 | Licensed node count lower bound |
apigo.license.cluster.on-provider-error | fail | Terminate or alert when node probing fails |
apigo.license.cluster.node-limit-action | fail | Terminate or alert when the node count is out of range |
Container deployments must mount the directory containing state.file to a persistent volume. Losing the state file under strict=true makes the service refuse to start; this prevents bypassing clock rollback detection by deleting the state file.
Failure handling
| Scenario | Behavior |
|---|---|
| Startup validation failure | Exception thrown; the process exits with a non-zero exit code |
| Scheduled runtime validation failure | Logs ERROR and exits according to the graceful shutdown policy with exit code 1 |
| Unexpected exceptions such as registry flapping | Logs ERROR and retries on the next cycle without exiting immediately |
Node count exceeds the upper limit and the policy is fail | Terminates; with warn, alerts and continues |
Exit code 1 distinguishes authorization problems from a normal shutdown (0), making it easy for orchestration systems to recognize an authorization issue rather than an ordinary restart.
Error codes
| Error code | Meaning |
|---|---|
L001 | License not configured |
L002 | Invalid License format |
L003 | Signature verification failed |
L004 | Invalid public key configuration |
L005 | Unsupported signature algorithm or missing dependency |
L006 | License not yet effective |
L007 | License expired |
L008 | Server MAC does not match the license |
L009 | Cluster node count exceeds the licensed maximum |
L010 | System clock rollback detected |
L011 | Current service is not covered by the license |
L012 | State file validation failed (possible tampering) |
L013 | State file unavailable |
L014 | Cluster node count probe failed |
L015 | Cluster node count below the licensed minimum |
Operations checklist
- MySQL and Redis available, charset
utf8mb4 -
db/mysql/ddl.sqland the necessary upgrade scripts executed - The three Java services use the same Redis and can reach each other over the network
- License file mounted read-only; state directory writable and persistent
- Services started in the correct order; the gateway can read routes
- Frontend Nginx configured with an API reverse proxy and static asset caching
- Logs, monitoring, and alerting channels connected