Documentation
Docs Home › Troubleshooting › Agent Enrollment

Agent Enrollment

Agent cannot enroll

Symptom

A new Agent does not appear online after start. Typical observations:

  • POST /api/v1/agents/register returns 4xx/403/429
  • zwallctl list-agents does not show the host
  • Agent journal shows bootstrap/TLS/profile errors
  • Hosting Agent refuses to start because a pre-token was left in YAML

Production example config keeps agents.auto_register: false. Admission is pre-register or admin create, then one-time bootstrap, then register.

Likely verified causes

  1. No pre-registration / create, and auto_register is false.
  2. Missing or consumed one-time bootstrap token (AGENT_PRE_TOKEN / AGENT_TOKEN; Hosting must not store server.pre_token in YAML).
  3. Hostname / expected_ip mismatch with the actual registration source IP (403 IP or identity mismatch).
  4. Invalid security_level (must be standard or maximum).
  5. Invalid Hosting vs Virtualization profile identity (400 Invalid Agent profile identity).
  6. Community already has 3 registered Agents (403 COMMUNITY_AGENT_LIMIT_REACHED).
  7. Enterprise license gate rejects Agent count (403 LicenseErrorResponse).
  8. RegisterRateLimiter on POST /api/v1/agents/register (429 / temporary ban).
  9. TLS verification failure (verify_tls: true; allow_insecure_remote_tls: false).
  10. Operator copied the stale start-agent path /etc/zwall/agent.yml. Real unit paths: Virtualization /etc/zcs/agent.yml; Hosting /etc/zwall-hosting/agent.yml.
  11. Wrong binary/unit: Hosting vs zwall-agent.service.

Diagnostic commands/endpoints

Manager must be ready first (Manager Unavailable).

zwallctl login --manager-url https://manager.example.com:8443 --username admin
zwallctl list-agents

Admin pre-register (requires hostname and expected_ip):

POST /api/v1/agents/pre-register
Authorization: Bearer <admin JWT>
{
  "hostname": "host-01",
  "expected_ip": "203.0.113.10",
  "security_level": "standard"
}

Optional Hosting identity fields: profile_type, profile_platform (JSON tag), profile_version, observation_only. Empty profile + observation_only: false is the Virtualization/default identity.

Agent register (Agent runtime, not a browser):

POST /api/v1/agents/register

Enterprise wraps ResolveRegistrationClientIP() plus RegisterRateLimiter(). Bootstrap token is required (PreToken). Response on success includes token, agent_id, security_level, token_expires_at.

On the node:

# Virtualization
sudo systemctl status zwall-agent
sudo journalctl -u zwall-agent -n 200 --no-pager

# Hosting (Enterprise)
sudo systemctl status zwall-hosting-agent
sudo journalctl -u zwall-hosting-agent -n 200 --no-pager

Confirm the config path in the unit ExecStart=, not folklore.

What each result means

Scroll sideways to see the full table. Use the arrow keys when focused.

ResultMeaning
400 Invalid request format on pre-registerJSON missing required hostname or expected_ip, or bind failure.
400 Invalid security_level: must be 'standard' or 'maximum'security_level set to something else. Empty defaults to standard. maximum is mTLS.
400 Invalid Agent profile identityProfile is not (all empty + not observation-only) and not Hosting hosting + plesk + hosting-plesk-observe-v1 or v2 with observation_only: true.
400 Invalid Hosting release identityHosting v2 register payload failed release identity checks.
400 Invalid hostname / Hostname cannot be an IP addressValidator or IP-as-hostname.
400 Invalid public IP addressexpected_ip unspecified, multicast, or loopback.
400 expiry_hours must not exceed 24Pre-register expiry cap. Default when omitted/≤0 is 1 hour.
400 Invalid pre-tokenBootstrap token failed format validation.
401 Bootstrap token is required for agent registrationPreToken empty.
401 Invalid bootstrap tokenUnknown, stale, or unparsable token (ErrStaleToken / ErrPreRegistrationNotFound).
403 Agent registration denied: IP address mismatchReported IP ≠ verified registration source, or pre-register expected IP mismatch.
403 Agent registration denied: identity mismatchDuplicate or conflicting identity.
403 Existing Agent recovery requires an explicit agent_idHostname already registered; recovery must name agent_id.
403 Community body code/error COMMUNITY_AGENT_LIMIT_REACHED, limit: 3Fourth registration-style enroll. Already-registered Agents may still heartbeat.
403 LicenseErrorResponse (success: false, code, message, license)Enterprise license gate on pre-register or register (OperationAgentPreRegister / OperationAgentRegister, LimitAgents).
403 Agent registration source could not be verifiedClient-IP resolver failed.
429 Registration temporarily bannedRegisterRateLimiter (3 attempts / 10 minute window; ban path returns retry_after_seconds).
503 Agent registration is unavailableRegistration repo / IP resolver / rate-limit identity not configured.
Hosting start error server.pre_token must not be stored in YAMLProduct-enforced Hosting validation. Use AGENT_PRE_TOKEN once, then unset.
TLS / x509 in Agent journalverify_tls: true rejected the Manager certificate.
Unit ExecStart /etc/zcs/agent.yml vs copied /etc/zwall/agent.ymlstale path string in zwallctl start message. Follow the unit.

Valid Hosting registration identity (from validRegistrationProfile): profile_type=hosting, platform=plesk, profile_version v1 or v2, observation_only=true. Virtualization uses empty profile fields and observation_only=false.

Safe remediation

  1. Confirm Manager /health/ready is 200.
  2. Pre-register or create the Agent as admin. Keep agents.auto_register: false.
  3. Place the one-time token in the Agent environment (AGENT_PRE_TOKEN / AGENT_TOKEN), not as a long-lived YAML JWT. Hosting unsets leftover AGENT_TOKEN / AGENT_PRE_TOKEN after config load.
  4. Match hostname and expected_ip to the address the Manager will see. Loopback is rejected as a public expected IP.
  5. Start the correct unit:
    • Virtualization: sudo systemctl start zwall-agent with /etc/zcs/agent.yml
    • Hosting: loader first, then Hosting Agent with /etc/zwall-hosting/agent.yml
  6. Confirm GET /api/v1/agents / zwallctl list-agents.
  7. Community: stay at 3 Agents or move to Enterprise. Do not “raise the limit” in Community config.
  8. Enterprise 403 license: inspect GET /api/v1/license/status and limits (not a public SKU list).
  9. Rate limit 429: wait for retry_after_seconds; do not script register in a tight loop.
  10. TLS: install a Manager certificate the Agent trusts. Do not flip allow_insecure_remote_tls except break-glass.

Do-not-do warnings

  • Do not leave AGENT_PRE_TOKEN in Hosting YAML or in a Hosting unit Environment= line. Tests forbid permanent bootstrap in the Hosting unit.
  • Do not copy sudo /usr/local/bin/zwall-agent --config /etc/zwall/agent.yml from zwallctl start as procedure.
  • Do not enable agents.auto_register to bypass pre-register in production. Example config is false; Manager warns if it is true.
  • Do not mix Hosting observation identity onto a Virtualization unit, or firewall programs onto a Hosting node.
  • Do not put bootstrap tokens in tickets, git, or ps argv.
  • Do not treat Community 3-Agent rejection as a Manager outage.
  • Do not publish default no-license entitlement numbers as a price list.

Escalation condition

Escalate when:

  • pre-register succeeds, token is unused, source IP matches expected_ip, TLS verifies, and register still returns identity mismatch
  • Hosting v2 returns Invalid Hosting release identity on an admitted Hosting bundle
  • Enterprise license gate denies enroll despite a license that should include Agents (license APIs vs commercial SKU is a known discrepancy)
  • Path prefix in the admitted release unit does not match any documented family

Edition

SHARED registration API. Community hard limit 3 Agents. Enterprise license gate and Hosting profile identity are ENTERPRISE_ONLY.

Status

SUPPORTED for pre-register → env token → register. NOT_SUPPORTED: leaving auto-register on as a production admission design.