--- host --- wg-access-dev Thu Jul 9 12:18:41 UTC 2026 --- containers --- wgaccess-backend Up 2 hours wgaccess-postgres Up 19 hours (healthy) --- backend health --- {"status":"ok","service":"wg-access-backend","environment":"dev"} postgres_container=wgaccess-postgres backend_container=wgaccess-backend --- db tables --- --- db columns peers/subscriptions/jobs-like --- --- db counts --- --- backend code grep allocator candidates --- /opt/wg-access/backend/app/models/core.py:19:class User(Base): /opt/wg-access/backend/app/models/core.py:30:class InviteCode(Base): /opt/wg-access/backend/app/models/core.py:42:class Order(Base): /opt/wg-access/backend/app/models/core.py:62:class Subscription(Base): /opt/wg-access/backend/app/models/core.py:81:class Peer(Base): /opt/wg-access/backend/app/models/core.py:84: # tunnel_ip uniqueness is enforced in PostgreSQL by partial unique index: /opt/wg-access/backend/app/models/core.py:85: # uq_peers_node_tunnel_ip_enabled (node_id, tunnel_ip) WHERE enabled = true, /opt/wg-access/backend/app/models/core.py:94: tunnel_ip: Mapped[str] = mapped_column(String(64), nullable=False) /opt/wg-access/backend/app/models/core.py:105:class ProvisioningJob(Base): /opt/wg-access/backend/app/models/core.py:106: __tablename__ = "provisioning_jobs" /opt/wg-access/backend/app/agent_trigger.py:10: The DB provisioning_jobs table remains the source of truth. /opt/wg-access/backend/app/db/base.py:4:class Base(DeclarativeBase): /opt/wg-access/backend/app/services/wireguard.py:41:def next_tunnel_ip(db: Session, node_id: str) -> str: /opt/wg-access/backend/app/services/wireguard.py:58: select(Peer.tunnel_ip).where( /opt/wg-access/backend/app/services/wireguard.py:77:def build_client_config(private_key: str, tunnel_ip: str, preshared_key: str) -> str: /opt/wg-access/backend/app/services/wireguard.py:80: allowed_ips = os.environ.get("WG_CLIENT_ALLOWED_IPS", "10.253.1.1/32").strip() /opt/wg-access/backend/app/services/wireguard.py:91: f"Address = {tunnel_ip}/32", /opt/wg-access/backend/app/services/wireguard.py:103: f"AllowedIPs = {allowed_ips}", /opt/wg-access/backend/app/config.py:4:class Settings(BaseSettings): /opt/wg-access/backend/app/config.py:9: class Config: /opt/wg-access/backend/app/api/admin.py:16: next_tunnel_ip, /opt/wg-access/backend/app/api/admin.py:24:class InviteCreateRequest(BaseModel): /opt/wg-access/backend/app/api/admin.py:29:class InviteResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:38: class Config: /opt/wg-access/backend/app/api/admin.py:65:class PeerResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:70: tunnel_ip: str /opt/wg-access/backend/app/api/admin.py:75: class Config: /opt/wg-access/backend/app/api/admin.py:86:class SubscriptionCreateRequest(BaseModel): /opt/wg-access/backend/app/api/admin.py:94:class SubscriptionCreateResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:100: tunnel_ip: str /opt/wg-access/backend/app/api/admin.py:111: # It creates a user, an active subscription, a WG peer and a pending enable_peer job. /opt/wg-access/backend/app/api/admin.py:129: tunnel_ip = next_tunnel_ip(db, payload.node_id) /opt/wg-access/backend/app/api/admin.py:132: client_config = build_client_config(private_key, tunnel_ip, preshared_key) /opt/wg-access/backend/app/api/admin.py:139: tunnel_ip=tunnel_ip, /opt/wg-access/backend/app/api/admin.py:148: action="enable_peer", /opt/wg-access/backend/app/api/admin.py:153: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/admin.py:173: tunnel_ip=peer.tunnel_ip, /opt/wg-access/backend/app/api/admin.py:184:class ExpireSubscriptionsResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:223: action="disable_peer", /opt/wg-access/backend/app/api/admin.py:227: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/admin.py:249:class CancelSubscriptionResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:287: action="disable_peer", /opt/wg-access/backend/app/api/admin.py:291: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/admin.py:315:class DisablePeerResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:320: tunnel_ip: str /opt/wg-access/backend/app/api/admin.py:325:def disable_peer(peer_id: UUID, db: Session = Depends(get_db)): /opt/wg-access/backend/app/api/admin.py:336: action="disable_peer", /opt/wg-access/backend/app/api/admin.py:340: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/admin.py:356: tunnel_ip=peer.tunnel_ip, /opt/wg-access/backend/app/api/admin.py:362:class JobResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:371: class Config: /opt/wg-access/backend/app/api/admin.py:381:class AdminSubscriptionResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:391: class Config: /opt/wg-access/backend/app/api/admin.py:395:class AdminUserPeerResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:400: tunnel_ip: str /opt/wg-access/backend/app/api/admin.py:406: class Config: /opt/wg-access/backend/app/api/admin.py:410:class AdminUserJobResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:420: class Config: /opt/wg-access/backend/app/api/admin.py:424:class AdminUserSummaryResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py:432: class Config: /opt/wg-access/backend/app/api/admin.py:436:class AdminUserDetailResponse(BaseModel): /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:19:class TestPeerRequest(BaseModel): /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:25:class TestPeerResponse(BaseModel): /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:29: tunnel_ip: str /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:63:def next_tunnel_ip(db: Session, node_id: str) -> str: /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:78: tunnel_ip = next_tunnel_ip(db, payload.node_id) /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:88: tunnel_ip=tunnel_ip, /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:97: action="enable_peer", /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:102: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/dev.py.BEFORE_CLIENT_CONFIG_RESPONSE.20260704-151636:118: tunnel_ip=peer.tunnel_ip, /opt/wg-access/backend/app/api/dev.py:14: next_tunnel_ip, /opt/wg-access/backend/app/api/dev.py:26:class TestPeerRequest(BaseModel): /opt/wg-access/backend/app/api/dev.py:32:class TestPeerResponse(BaseModel): /opt/wg-access/backend/app/api/dev.py:36: tunnel_ip: str /opt/wg-access/backend/app/api/dev.py:58: tunnel_ip = next_tunnel_ip(db, payload.node_id) /opt/wg-access/backend/app/api/dev.py:62: client_config = build_client_config(private_key, tunnel_ip, preshared_key) /opt/wg-access/backend/app/api/dev.py:69: tunnel_ip=tunnel_ip, /opt/wg-access/backend/app/api/dev.py:78: action="enable_peer", /opt/wg-access/backend/app/api/dev.py:83: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/dev.py:99: tunnel_ip=peer.tunnel_ip, /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:16:class TestPeerRequest(BaseModel): /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:22:class TestPeerResponse(BaseModel): /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:26: tunnel_ip: str /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:36:def next_tunnel_ip(db: Session, node_id: str) -> str: /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:51: tunnel_ip = next_tunnel_ip(db, payload.node_id) /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:58: tunnel_ip=tunnel_ip, /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:67: action="enable_peer", /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:72: "tunnel_ip": peer.tunnel_ip, /opt/wg-access/backend/app/api/dev.py.BEFORE_REAL_WG_KEYS.20260704-132545:88: tunnel_ip=peer.tunnel_ip, /opt/wg-access/backend/app/api/agent.py:21:class AgentPeerResponse(BaseModel): /opt/wg-access/backend/app/api/agent.py:26: tunnel_ip: str /opt/wg-access/backend/app/api/agent.py:30: class Config: /opt/wg-access/backend/app/api/agent.py:50:class AgentJobResponse(BaseModel): /opt/wg-access/backend/app/api/agent.py:60: class Config: /opt/wg-access/backend/app/api/agent.py:64:class FailRequest(BaseModel): /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:16:class InviteCreateRequest(BaseModel): /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:21:class InviteResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:30: class Config: /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:56:class PeerResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:61: tunnel_ip: str /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:66: class Config: /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:76:class JobResponse(BaseModel): /opt/wg-access/backend/app/api/admin.py.BEFORE_DISABLE_PEER.20260704-151253:85: class Config: /opt/wg-access/backend/app/api/agent.py.BEFORE_AGENT_PEERS_SYNC.20260704-133954:21:class AgentJobResponse(BaseModel): /opt/wg-access/backend/app/api/agent.py.BEFORE_AGENT_PEERS_SYNC.20260704-133954:31: class Config: /opt/wg-access/backend/app/api/agent.py.BEFORE_AGENT_PEERS_SYNC.20260704-133954:35:class FailRequest(BaseModel): --- agent/service files --- /etc/systemd/system/multi-user.target.wants/wg-access-trigger-watch.service /etc/systemd/system/timers.target.wants/wg-access-reconcile.timer /etc/systemd/system/wg-access-agent.path /etc/systemd/system/wg-access-agent.service /etc/systemd/system/wg-access-agent.timer /etc/systemd/system/wg-access-reconcile.service /etc/systemd/system/wg-access-reconcile.timer /etc/systemd/system/wg-access-trigger-watch.service /opt/wg-access/STATUS-STEP-006_AGENT_PULL_API_OK.txt /opt/wg-access/STATUS-STEP-007_AGENT_DRY_RUN_OK.txt /opt/wg-access/STATUS-STEP-008_AGENT_TIMER_OK.txt /opt/wg-access/STATUS-STEP-010_AGENT_SSH_TO_VM100_OK.txt /opt/wg-access/STATUS-STEP-012_REAL_AGENT_PROVISION_VM100_OK.txt /opt/wg-access/STATUS-STEP-014_AGENT_RECONCILE_SYNC_OK.txt /opt/wg-access/STATUS-STEP-020C_AGENT_TIMER_REAL_PERIODIC_OK.txt /opt/wg-access/agent /opt/wg-access/agent/__pycache__/wg_access_agent.cpython-311.pyc /opt/wg-access/agent/agent.env /opt/wg-access/agent/agent.env.BEFORE_MGTS_REMOTE_HOST_20260706-183324 /opt/wg-access/agent/agent.env.BEFORE_REAL_SSH_WG_SET.20260704-132120 /opt/wg-access/agent/logs/agent.log /opt/wg-access/agent/ssh/wg_access_agent_ed25519 /opt/wg-access/agent/ssh/wg_access_agent_ed25519.pub /opt/wg-access/agent/wg_access_agent.py /opt/wg-access/agent/wg_access_agent.py.BEFORE_REAL_SSH_WG_SET.20260704-132120 /opt/wg-access/agent/wg_access_agent.py.BEFORE_RECONCILE_SYNC.20260704-134532 /opt/wg-access/backend/app/agent_trigger.py /opt/wg-access/backups/STEP_042C2_RECOVER_REAPPLY_EVENT_TRIGGER_CLEAN_20260709-095639 /opt/wg-access/backups/STEP_042C2_RECOVER_REAPPLY_EVENT_TRIGGER_CLEAN_20260709-095639/wg-access-agent.path.before_042c2 /opt/wg-access/backups/STEP_042C_AGENT_EVENT_TRIGGER_FILE_PATH_IMPLEMENT_20260709-095315 /opt/wg-access/backups/STEP_042D2_CLEANUP_RECONCILE_UNIT_DOCUMENTATION_20260709-100101 /opt/wg-access/backups/STEP_042D2_CLEANUP_RECONCILE_UNIT_DOCUMENTATION_20260709-100101/wg-access-reconcile.service.before /opt/wg-access/backups/STEP_042D2_CLEANUP_RECONCILE_UNIT_DOCUMENTATION_20260709-100101/wg-access-reconcile.timer.before /opt/wg-access/backups/STEP_042D_RECONCILE_ON_BOOT_AND_SAFETY_TIMER_IMPLEMENT_20260709-095902 /opt/wg-access/backups/STEP_042G_RELIABLE_EVENT_TRIGGER_DIR_SPOOL_IMPLEMENT_20260709-102432 /opt/wg-access/backups/STEP_042G_RELIABLE_EVENT_TRIGGER_DIR_SPOOL_IMPLEMENT_20260709-102432/agent_trigger.py.before /opt/wg-access/backups/STEP_042G_RELIABLE_EVENT_TRIGGER_DIR_SPOOL_IMPLEMENT_20260709-102432/wg-access-agent.path.before /opt/wg-access/backups/STEP_042I3_FIX_BACKEND_TRIGGER_BIND_MOUNT_20260709-104537 /opt/wg-access/backups/STEP_042I_REPLACE_EVENT_TRIGGER_WITH_RELIABLE_HOST_SIDE_WATCHER_20260709-103758 /opt/wg-access/backups/STEP_042I_REPLACE_EVENT_TRIGGER_WITH_RELIABLE_HOST_SIDE_WATCHER_20260709-103758/agent_trigger.py.before /opt/wg-access/backups/STEP_042I_REPLACE_EVENT_TRIGGER_WITH_RELIABLE_HOST_SIDE_WATCHER_20260709-103758/wg-access-agent.path.before /opt/wg-access/backups/STEP_042K_CHECKPOINT_AGENT_AUTOMATION_AND_REBOOT_RECOVERY_OK_20260709-111005 /opt/wg-access/backups/STEP_042K_CHECKPOINT_AGENT_AUTOMATION_OK_20260709-105135 /opt/wg-access/backups/step020b/wg-access-agent.service.20260704-160536.bak /opt/wg-access/backups/step020b/wg-access-agent.timer.20260704-160536.bak /opt/wg-access/backups/step020c/wg-access-agent.timer.20260704-160647.bak /opt/wg-access/docker-compose.step042i3-trigger-bind.yml /opt/wg-access/runtime/agent-trigger /opt/wg-access/runtime/agent-trigger/pending.trigger /opt/wg-access/status/STEP_042K_CHECKPOINT_AGENT_AUTOMATION_AND_REBOOT_RECOVERY_OK_20260709-111005.json /usr/local/sbin/wg-access-agent-job-selector-plan.py /usr/local/sbin/wg-access-agent-selector-apply.py /usr/local/sbin/wg-access-agent-selector-contract-dry-run.py /usr/local/sbin/wg-access-agent-selector-remote-plan.py /usr/local/sbin/wg-access-reconcile-now.sh /usr/local/sbin/wg-access-trigger-watch.py --- watcher/reconcile services --- active enabled active enabled