#cloud-config # Aegis402 — VPS bootstrap (SporeStack / Hetzner / any cloud-init compatible host) # Hardened, no telemetry, no third-party agent. # Replace AEGIS402_PUBLIC_URL and AEGIS402_WALLET_PASS placeholders before launch. hostname: aegis402 preserve_hostname: false manage_etc_hosts: true timezone: UTC users: - name: aegis sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash lock_passwd: true ssh_authorized_keys: - REPLACE_WITH_YOUR_SSH_PUBKEY package_update: true package_upgrade: true packages: - python3.12 - python3.12-venv - python3-pip - git - ufw - fail2ban - sqlite3 - nginx - certbot - python3-certbot-nginx - unattended-upgrades write_files: - path: /etc/aegis402.env permissions: '0600' owner: aegis:aegis content: | AEGIS402_X402_ENABLED=1 AEGIS402_X402_STRICT=1 AEGIS402_X402_FACILITATOR=https://x402.org/facilitator AEGIS402_PUBLIC_URL=https://REPLACE_DOMAIN/ AEGIS402_WALLET_PASS=REPLACE_32CHAR_RANDOM_PASS_FROM_LOCAL - path: /etc/systemd/system/aegis402.service content: | [Unit] Description=Aegis402 API After=network-online.target Wants=network-online.target [Service] Type=simple User=aegis Group=aegis WorkingDirectory=/home/aegis/aegis402 EnvironmentFile=/etc/aegis402.env ExecStart=/home/aegis/aegis402/venv/bin/uvicorn src.server:app \ --host 127.0.0.1 --port 8743 --workers 2 --log-level info Restart=always RestartSec=5 NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=read-only ReadWritePaths=/home/aegis/aegis402/data LimitNOFILE=4096 [Install] WantedBy=multi-user.target - path: /etc/systemd/system/aegis402-ingest.service content: | [Unit] Description=Aegis402 ingest GHSA + KEV After=network-online.target Wants=network-online.target [Service] Type=oneshot User=aegis Group=aegis WorkingDirectory=/home/aegis/aegis402 EnvironmentFile=/etc/aegis402.env ExecStart=/home/aegis/aegis402/venv/bin/python -m src.ingest_ghsa ExecStart=/home/aegis/aegis402/venv/bin/python -m src.ingest_kev Nice=10 TimeoutStartSec=900 - path: /etc/systemd/system/aegis402-ingest.timer content: | [Unit] Description=Aegis402 ingest every 60 min Requires=aegis402-ingest.service [Timer] OnBootSec=3min OnUnitActiveSec=60min RandomizedDelaySec=120 Persistent=true Unit=aegis402-ingest.service [Install] WantedBy=timers.target - path: /etc/nginx/sites-available/aegis402 content: | server { listen 80 default_server; server_name _; location / { proxy_pass http://127.0.0.1:8743; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 30s; client_max_body_size 256k; } } runcmd: # Firewall - ufw default deny incoming - ufw default allow outgoing - ufw allow 22/tcp - ufw allow 80/tcp - ufw allow 443/tcp - ufw --force enable # Unattended security upgrades - dpkg-reconfigure -f noninteractive unattended-upgrades # App install - sudo -u aegis git clone https://REPLACE_GIT_REMOTE /home/aegis/aegis402 - sudo -u aegis python3.12 -m venv /home/aegis/aegis402/venv - sudo -u aegis /home/aegis/aegis402/venv/bin/pip install --upgrade pip - sudo -u aegis /home/aegis/aegis402/venv/bin/pip install -r /home/aegis/aegis402/requirements.txt - sudo -u aegis mkdir -p /home/aegis/aegis402/data - sudo -u aegis /home/aegis/aegis402/venv/bin/python -c "from src.db import init_db; init_db()" - sudo -u aegis /home/aegis/aegis402/venv/bin/python -m src.wallet - sudo -u aegis /home/aegis/aegis402/venv/bin/python -m src.ingest_ghsa - sudo -u aegis /home/aegis/aegis402/venv/bin/python -m src.ingest_kev # Nginx + TLS - ln -s /etc/nginx/sites-available/aegis402 /etc/nginx/sites-enabled/aegis402 - rm -f /etc/nginx/sites-enabled/default - nginx -t && systemctl restart nginx # Replace REPLACE_DOMAIN below before launch: # - certbot --nginx -d REPLACE_DOMAIN --non-interactive --agree-tos -m REPLACE_EMAIL --redirect # Services - systemctl daemon-reload - systemctl enable --now aegis402.service - systemctl enable --now aegis402-ingest.timer final_message: "Aegis402 bootstrap complete. Set DNS to this IP, then run certbot."