{"slug": "paperclip-ai-deployment-guide-on-oracle-cloud-linux-vps-arm-via-coolify", "title": "Paperclip AI Deployment Guide on Oracle Cloud Linux VPS (ARM) via Coolify", "summary": "A developer published a step-by-step guide for self-hosting the open-source Paperclip agent orchestration platform on an Oracle Cloud Infrastructure ARM64 VPS, using Coolify, Docker Compose, Traefik, Let's Encrypt, PostgreSQL 17, and OpenRouter. The walkthrough covers DNS A-record setup, OCI security-list ingress rules for ports 80 and 443, host-level iptables persistence, generating a 32-byte BETTER_AUTH_SECRET, and a Docker Compose stack running the ghcr.io/paperclipai/paperclip image behind Traefik on port 3100.", "body_md": "A complete step-by-step guide to deploy and host the open-source **Paperclip agent orchestration platform** on an **Oracle Cloud Infrastructure (OCI) ARM64 VPS** using **Coolify, Docker Compose, Traefik, Let's Encrypt SSL, PostgreSQL, and OpenRouter**.\n\n**Security note:** Replace all example passwords, secrets, API keys, and domain names with your own values. Never commit secrets or API keys to Git.\n\nThe deployment consists of the following components:\n\n| Component | Technology | \n|---|---|\n| Host | Oracle Cloud Infrastructure (OCI) Ampere A1 ARM64 VPS | \n| Operating System | Ubuntu | \n| Deployment/Orchestration | Coolify | \n| Container Runtime | Docker | \n| Reverse Proxy | Traefik | \n| SSL | Let's Encrypt | \n| Database | PostgreSQL 17 Alpine | \n| Application | `ghcr.io/paperclipai/paperclip:latest` | \n| Domain | `https://paperclip.arpann8n.qzz.io` | \n| AI Gateway | OpenRouter API | \n| Agent Runtime | OpenCode | \n\n```\nUser Browser\n     |\n     | HTTPS :443\n     v\nOracle Cloud VPS\n     |\n     v\nCoolify / Traefik\n     |\n     | HTTPS termination + routing\n     v\nPaperclip :3100\n     |\n     +--------------------+\n     |                    |\n     v                    v\nPostgreSQL 17        OpenRouter API\n     |                    |\n     v                    v\nPersistent Data       AI Model Provider\n```\n\nBefore starting, make sure you have:\n\nOpen your DNS provider dashboard and create an **A record**.\n\n| Setting | Value | \n|---|---|\n| Name / Host | `paperclip` | \n| Type | `A` | \n| Target / Value | Your Oracle Cloud VPS public IPv4 address | \n| TTL | Automatic or `300` seconds | \n\nThe resulting hostname should resolve to your VPS, for example:\n\n```\npaperclip.example.com\n```\n\nThis guide uses:\n\n```\nhttps://yourDomain.com\n```\n\nFrom your local machine:\n\n```\nnslookup yourDomain.com\n```\n\nor:\n\n```\ndig yourDomain.com\n```\n\nThe returned IP should match your Oracle Cloud VPS public IPv4 address.\n\nLog in to the Oracle Cloud Console.\n\nNavigate to:\n\n```\nNetworking\n  → Virtual Cloud Networks\n    → Your VCN\n      → Security Lists\n        → Default Security List\n```\n\nUnder **Ingress Rules**, click **Add Ingress Rules**.\n\nCreate an inbound rule with:\n\n| Field | Value | \n|---|---|\n| Source CIDR | `0.0.0.0/0` | \n| Protocol | TCP | \n| Destination Port Range | `80,443` | \n| Description | Allow HTTP and HTTPS web traffic | \n\nSave the rule.\n\nSome Oracle Ubuntu images may have host-level firewall rules that prevent incoming HTTP/HTTPS traffic.\n\nAllow ports 80 and 443:\n\n```\n# Allow HTTPS (443) at the top of the INPUT chain\nsudo iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT\n\n# Allow HTTP (80) at the top of the INPUT chain\nsudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT\n```\n\nInstall persistent firewall-rule support:\n\n```\nsudo apt-get update\nsudo apt-get install -y iptables-persistent netfilter-persistent\n```\n\nSave the rules:\n\n```\nsudo netfilter-persistent save\n```\n\nVerify:\n\n```\nsudo iptables -L INPUT -n --line-numbers\n```\n\nYou should see ports **80** and **443** with target `ACCEPT`, preferably before any broad `REJECT` or `DROP` rule.\n\n**Important:** Firewall configuration can differ between Ubuntu images and OCI networking setups. Review existing rules before changing them.\n\nGenerate a secure 32-byte hexadecimal secret on the VPS:\n\n```\nopenssl rand -hex 32\n```\n\nExample output:\n\n```\n9b7c0f...64-character-secret...e21a\n```\n\nSave the complete 64-character value securely.\n\nThis value will be used as:\n\n```\nBETTER_AUTH_SECRET\n```\n\nDo not publish it or commit it to Git.\n\nOpen your **Coolify Dashboard**.\n\n```\nProject\n  → + New\n    → Docker Compose\n```\n\nPaste the following Docker Compose configuration:\n\n```\nversion: '3.8'\n\nservices:\n  db:\n    image: postgres:17-alpine\n    restart: unless-stopped\n    environment:\n      POSTGRES_DB: paperclip\n      POSTGRES_USER: paperclip\n      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgresSecurePass123}\n    volumes:\n      - pgdata:/var/lib/postgresql/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U paperclip -d paperclip\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n\n  paperclip:\n    image: ghcr.io/paperclipai/paperclip:latest\n    restart: unless-stopped\n    depends_on:\n      db:\n        condition: service_healthy\n    environment:\n      NODE_ENV: production\n      PORT: \"3100\"\n      SERVE_UI: \"true\"\n      HOST: \"0.0.0.0\"\n      PAPERCLIP_DEPLOYMENT_MODE: \"authenticated\"\n      PAPERCLIP_DEPLOYMENT_EXPOSURE: \"public\"\n      PAPERCLIP_PUBLIC_URL: \"https://yourDomain.com\"\n      BETTER_AUTH_SECRET: \"${BETTER_AUTH_SECRET}\"\n      DATABASE_URL: \"postgres://paperclip:${POSTGRES_PASSWORD:-postgresSecurePass123}@db:5432/paperclip\"\n      PAPERCLIP_SECRETS_MASTER_KEY_FILE: \"/paperclip/instances/default/secrets/master.key\"\n      OPENROUTER_API_KEY: \"${OPENROUTER_API_KEY}\"\n    volumes:\n      - paperclip-data:/paperclip\n\nvolumes:\n  pgdata:\n  paperclip-data:\n```\n\nIf you use a different domain, update:\n\n```\nPAPERCLIP_PUBLIC_URL: \"https://yourDomain.com\"\n```\n\nto your actual public URL.\n\nFor example:\n\n```\nPAPERCLIP_PUBLIC_URL: \"https://yourDomain.com\"\n```\n\nIn Coolify, open the stack's **Environment Variables** section.\n\nAdd:\n\n```\nPOSTGRES_PASSWORD=<A-STRONG-RANDOM-PASSWORD>\nBETTER_AUTH_SECRET=<OUTPUT-FROM-openssl-rand-hex-32>\nOPENROUTER_API_KEY=sk-or-v1-xxxxxxxxxxxxxxxxxxxx\n```\n\nYou can generate one with:\n\n```\nopenssl rand -base64 32\n```\n\nUse the generated value for:\n\n```\nPOSTGRES_PASSWORD\n```\n\nDo **not** copy these example values into production:\n\n```\nPOSTGRES_PASSWORD=replace-with-your-own-password\nBETTER_AUTH_SECRET=replace-with-your-own-secret\nOPENROUTER_API_KEY=sk-or-v1-replace-with-your-own-key\n```\n\nOpen the **Domains** tab in the Coolify service view.\n\nClick:\n\n```\n+ Add Domain\n```\n\nConfigure:\n\n| Setting | Value | \n|---|---|\n| Service | `paperclip` | \n| Image | `ghcr.io/paperclipai/paperclip:latest` | \n| Protocol | `https` | \n| Domain | `paperclip.arpann8n.qzz.io` | \n| Port | `3100` | \n| Path | Leave empty | \n\nClick **Save**.\n\nCoolify/Traefik will use this configuration to route HTTPS traffic to Paperclip's internal port `3100`.\n\nClick **Deploy** in the top-right corner of Coolify.\n\nCoolify should:\n\nAfter deployment, visit:\n\n```\nhttps://yourDomain.com\n```\n\nBecause the instance is configured with authenticated public deployment mode, browser-based self-registration is disabled.\n\nA one-time bootstrap link must be generated from inside the Paperclip container.\n\nIn Coolify:\n\n```\nObserve & troubleshoot\n  → Terminal\n```\n\nSelect the:\n\n```\npaperclip\n```\n\ncontainer.\n\nRun:\n\n```\nchown -R node:node /paperclip\nchmod -R 700 /paperclip/instances/default/secrets\n```\n\nThen generate the CEO bootstrap URL:\n\n```\nsu -s /bin/sh node -c \"pnpm paperclipai auth bootstrap-ceo\"\n```\n\nThe command should output a single-use URL similar to:\n\n```\nhttps://yourDomain.com/auth/claim?token=...\n```\n\nOpen that URL in your browser.\n\nComplete the administrator registration:\n\nTreat the bootstrap URL as a credential. Do not post it publicly or commit it to source control.\n\nDuring the Paperclip onboarding wizard, you may see a screen asking you to connect a model with **Claude** and **OpenAI** buttons.\n\nThose fields may perform provider-specific API validation against Anthropic/OpenAI endpoints. An OpenRouter key is not necessarily valid for those direct-provider checks.\n\nInstead:\n\n```\nUse subscription\n```\n\nor skip that step if the UI provides a skip option.\n\nContinue through the remaining onboarding steps until you reach the main Paperclip workspace dashboard.\n\nHeadless container environments may not provide the terminal capabilities required by some CLI-based agent runtimes.\n\nFor this deployment, configure the CEO agent to use an **API-based OpenCode runtime** through OpenRouter.\n\nFrom the Paperclip workspace:\n\n```\nCompany name\n  → Company Settings\n```\n\nAlternatively, navigate to:\n\n```\n/company/settings/secrets\n+ New secret\n```\n\n| Field | Value | \n|---|---|\n| Who provides the value? | Organization | \n| Type | Managed value | \n| Name | `OPENROUTER_API_KEY` | \n| Value | Your OpenRouter API key | \n| Key | `OPENROUTER_API_KEY` | \n\nYour API key will normally look similar to:\n\n```\nsk-or-v1-...\n```\n\nIn the left navigation:\n\n```\nAgents\n  → CEO\n  → Secrets & variables\n```\n\nUnder:\n\n```\nAPI ACCESS (NO ENV VAR)\n```\n\nadd:\n\n```\nOPENROUTER_API_KEY\nSave changes\n```\n\nOpen the CEO agent settings.\n\n```\nHarness / Runtime\n```\n\n| Setting | Value | \n|---|---|\n| Adapter type | `OpenCode` | \n| Model | Your desired OpenRouter model slug | \n\nExamples:\n\n```\nopenai/gpt-4o-mini\nanthropic/claude-3.5-sonnet\n```\n\nor another model supported by your OpenRouter account and current Paperclip/OpenCode integration.\n\nModel availability, names, pricing, and provider support can change. Use a currently supported model slug from OpenRouter/Paperclip rather than assuming an older model name will remain available.\n\n```\nTest again\nVerify\n```\n\nYou should receive a successful connection result.\n\nThen click:\n\n```\nSave changes\n```\n\nIf the CEO agent still shows an old failure banner:\n\n```\nOverview\n  → Clear error\n```\n\nThis clears the previous runtime error state after the configuration has been corrected.\n\n```\nTasks\n  → Paperclip onboarding (SKO-1)\n```\n\nSend a test message such as:\n\n```\nHello, please proceed with the onboarding plan.\n```\n\nThe CEO agent should process the request through the configured OpenCode runtime and OpenRouter API.\n\nA successful flow should look like:\n\n```\nPaperclip Task\n      |\n      v\nCEO Agent\n      |\n      v\nOpenCode Adapter\n      |\n      v\nOpenRouter API\n      |\n      v\nSelected AI Model\n      |\n      v\nResponse\n      |\n      v\nPaperclip Task\n```\n\nCheck DNS:\n\n```\nnslookup paperclip.arpann8n.qzz.io\n```\n\nConfirm that it resolves to the correct OCI public IP.\n\nThen verify OCI ingress rules allow:\n\n```\nTCP 80\nTCP 443\n```\n\nAlso inspect the Ubuntu firewall:\n\n```\nsudo iptables -L INPUT -n --line-numbers\n```\n\nCheck all of the following:\n\nHTTP port 80 can be particularly important when using HTTP-01 certificate validation.\n\nCheck the PostgreSQL container:\n\n```\ndocker ps\n```\n\nInspect logs through Coolify or Docker:\n\n```\ndocker logs <postgres-container>\n```\n\nThe PostgreSQL health check is:\n\n```\npg_isready -U paperclip -d paperclip\n```\n\nMake sure the application and database use the same:\n\n```\nPOSTGRES_PASSWORD\n```\n\nInside the Paperclip container, check the volume permissions:\n\n```\nls -la /paperclip\nls -la /paperclip/instances/default\nls -la /paperclip/instances/default/secrets\n```\n\nThen run:\n\n```\nchown -R node:node /paperclip\nchmod -R 700 /paperclip/instances/default/secrets\n```\n\nRetry:\n\n```\nsu -s /bin/sh node -c \"pnpm paperclipai auth bootstrap-ceo\"\n```\n\nIf the agent reports a terminal or ACP access failure, verify that the CEO agent is not configured to use a CLI runtime that requires an interactive terminal.\n\nCheck:\n\n```\nAgents\n  → CEO\n  → Harness / Runtime\n```\n\nUse:\n\n```\nAdapter type: OpenCode\n```\n\nand ensure:\n\n```\nOPENROUTER_API_KEY\n```\n\nis available to the agent.\n\nVerify the secret exists at the company level:\n\n```\nCompany Settings\n  → Secrets\n```\n\nConfirm the key is:\n\n```\nOPENROUTER_API_KEY\n```\n\nThen verify it is bound to:\n\n```\nCEO\n  → Secrets & variables\n```\n\nDo not confuse:\n\n```\nOPENROUTER_API_KEY\n```\n\nwith provider-specific credentials such as:\n\n```\nANTHROPIC_API_KEY\nOPENAI_API_KEY\n```\n\nBefore exposing the deployment to the public internet, review the following.\n\n`POSTGRES_PASSWORD` is strong and unique.`BETTER_AUTH_SECRET` was generated randomly.`5432` is `3100` is \n\n```\nopenssl rand -hex 32\nopenssl rand -base64 32\nnslookup paperclip.arpann8n.qzz.io\nsudo iptables -L INPUT -n --line-numbers\nsudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT\nsudo iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT\nsudo netfilter-persistent save\nsudo ss -tulpn\n```\n\nThe complete deployment process is:\n\n```\n1. Create OCI ARM64 Ubuntu VPS\n           ↓\n2. Point DNS A record to VPS\n           ↓\n3. Allow TCP 80/443 in OCI VCN\n           ↓\n4. Allow TCP 80/443 on Ubuntu firewall\n           ↓\n5. Generate BETTER_AUTH_SECRET\n           ↓\n6. Create Docker Compose stack in Coolify\n           ↓\n7. Configure PostgreSQL + Paperclip\n           ↓\n8. Add Coolify environment variables\n           ↓\n9. Configure Paperclip domain → port 3100\n           ↓\n10. Deploy stack\n           ↓\n11. Generate CEO bootstrap URL\n           ↓\n12. Create administrator account\n           ↓\n13. Complete onboarding\n           ↓\n14. Create OPENROUTER_API_KEY secret\n           ↓\n15. Bind secret to CEO agent\n           ↓\n16. Configure OpenCode runtime\n           ↓\n17. Select OpenRouter model\n           ↓\n18. Verify connection\n           ↓\n19. Send test task\n           ↓\n20. Paperclip agent responds through OpenRouter\n```\n\nAfter completing the guide, the deployment should provide:\n\nThis guide is based on the configuration described in the deployment procedure. Paperclip, Coolify, OpenRouter, Docker images, model availability, and their configuration interfaces can change over time.\n\nBefore production use, verify the current Paperclip and OpenRouter documentation for:\n\nNever expose database credentials, authentication secrets, bootstrap URLs, or API keys in public repositories, screenshots, logs, or issue trackers.", "url": "https://wpnews.pro/news/paperclip-ai-deployment-guide-on-oracle-cloud-linux-vps-arm-via-coolify", "canonical_source": "https://dev.to/arpandhara/paperclip-ai-deployment-guide-on-oracle-cloud-arm-via-coolify-4ieh", "published_at": "2026-09-28 09:22:18+00:00", "updated_at": "2026-09-28 09:49:08.643532+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-infrastructure", "mlops", "developer-tools"], "entities": ["Paperclip", "Oracle Cloud Infrastructure", "Coolify", "Docker Compose", "Traefik", "Let's Encrypt", "PostgreSQL", "OpenRouter"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/paperclip-ai-deployment-guide-on-oracle-cloud-linux-vps-arm-via-coolify", "markdown": "https://wpnews.pro/news/paperclip-ai-deployment-guide-on-oracle-cloud-linux-vps-arm-via-coolify.md", "text": "https://wpnews.pro/news/paperclip-ai-deployment-guide-on-oracle-cloud-linux-vps-arm-via-coolify.txt", "jsonld": "https://wpnews.pro/news/paperclip-ai-deployment-guide-on-oracle-cloud-linux-vps-arm-via-coolify.jsonld"}}