# Paperclip AI Deployment Guide on Oracle Cloud Linux VPS (ARM) via Coolify

> Source: <https://dev.to/arpandhara/paperclip-ai-deployment-guide-on-oracle-cloud-arm-via-coolify-4ieh>
> Published: 2026-09-28 09:22:18+00:00

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**.

**Security note:** Replace all example passwords, secrets, API keys, and domain names with your own values. Never commit secrets or API keys to Git.

The deployment consists of the following components:

| Component | Technology | 
|---|---|
| Host | Oracle Cloud Infrastructure (OCI) Ampere A1 ARM64 VPS | 
| Operating System | Ubuntu | 
| Deployment/Orchestration | Coolify | 
| Container Runtime | Docker | 
| Reverse Proxy | Traefik | 
| SSL | Let's Encrypt | 
| Database | PostgreSQL 17 Alpine | 
| Application | `ghcr.io/paperclipai/paperclip:latest` | 
| Domain | `https://paperclip.arpann8n.qzz.io` | 
| AI Gateway | OpenRouter API | 
| Agent Runtime | OpenCode | 

```
User Browser
     |
     | HTTPS :443
     v
Oracle Cloud VPS
     |
     v
Coolify / Traefik
     |
     | HTTPS termination + routing
     v
Paperclip :3100
     |
     +--------------------+
     |                    |
     v                    v
PostgreSQL 17        OpenRouter API
     |                    |
     v                    v
Persistent Data       AI Model Provider
```

Before starting, make sure you have:

Open your DNS provider dashboard and create an **A record**.

| Setting | Value | 
|---|---|
| Name / Host | `paperclip` | 
| Type | `A` | 
| Target / Value | Your Oracle Cloud VPS public IPv4 address | 
| TTL | Automatic or `300` seconds | 

The resulting hostname should resolve to your VPS, for example:

```
paperclip.example.com
```

This guide uses:

```
https://yourDomain.com
```

From your local machine:

```
nslookup yourDomain.com
```

or:

```
dig yourDomain.com
```

The returned IP should match your Oracle Cloud VPS public IPv4 address.

Log in to the Oracle Cloud Console.

Navigate to:

```
Networking
  → Virtual Cloud Networks
    → Your VCN
      → Security Lists
        → Default Security List
```

Under **Ingress Rules**, click **Add Ingress Rules**.

Create an inbound rule with:

| Field | Value | 
|---|---|
| Source CIDR | `0.0.0.0/0` | 
| Protocol | TCP | 
| Destination Port Range | `80,443` | 
| Description | Allow HTTP and HTTPS web traffic | 

Save the rule.

Some Oracle Ubuntu images may have host-level firewall rules that prevent incoming HTTP/HTTPS traffic.

Allow ports 80 and 443:

```
# Allow HTTPS (443) at the top of the INPUT chain
sudo iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT

# Allow HTTP (80) at the top of the INPUT chain
sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT
```

Install persistent firewall-rule support:

```
sudo apt-get update
sudo apt-get install -y iptables-persistent netfilter-persistent
```

Save the rules:

```
sudo netfilter-persistent save
```

Verify:

```
sudo iptables -L INPUT -n --line-numbers
```

You should see ports **80** and **443** with target `ACCEPT`, preferably before any broad `REJECT` or `DROP` rule.

**Important:** Firewall configuration can differ between Ubuntu images and OCI networking setups. Review existing rules before changing them.

Generate a secure 32-byte hexadecimal secret on the VPS:

```
openssl rand -hex 32
```

Example output:

```
9b7c0f...64-character-secret...e21a
```

Save the complete 64-character value securely.

This value will be used as:

```
BETTER_AUTH_SECRET
```

Do not publish it or commit it to Git.

Open your **Coolify Dashboard**.

```
Project
  → + New
    → Docker Compose
```

Paste the following Docker Compose configuration:

```
version: '3.8'

services:
  db:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: paperclip
      POSTGRES_USER: paperclip
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgresSecurePass123}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U paperclip -d paperclip"]
      interval: 5s
      timeout: 5s
      retries: 5

  paperclip:
    image: ghcr.io/paperclipai/paperclip:latest
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      NODE_ENV: production
      PORT: "3100"
      SERVE_UI: "true"
      HOST: "0.0.0.0"
      PAPERCLIP_DEPLOYMENT_MODE: "authenticated"
      PAPERCLIP_DEPLOYMENT_EXPOSURE: "public"
      PAPERCLIP_PUBLIC_URL: "https://yourDomain.com"
      BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET}"
      DATABASE_URL: "postgres://paperclip:${POSTGRES_PASSWORD:-postgresSecurePass123}@db:5432/paperclip"
      PAPERCLIP_SECRETS_MASTER_KEY_FILE: "/paperclip/instances/default/secrets/master.key"
      OPENROUTER_API_KEY: "${OPENROUTER_API_KEY}"
    volumes:
      - paperclip-data:/paperclip

volumes:
  pgdata:
  paperclip-data:
```

If you use a different domain, update:

```
PAPERCLIP_PUBLIC_URL: "https://yourDomain.com"
```

to your actual public URL.

For example:

```
PAPERCLIP_PUBLIC_URL: "https://yourDomain.com"
```

In Coolify, open the stack's **Environment Variables** section.

Add:

```
POSTGRES_PASSWORD=<A-STRONG-RANDOM-PASSWORD>
BETTER_AUTH_SECRET=<OUTPUT-FROM-openssl-rand-hex-32>
OPENROUTER_API_KEY=sk-or-v1-xxxxxxxxxxxxxxxxxxxx
```

You can generate one with:

```
openssl rand -base64 32
```

Use the generated value for:

```
POSTGRES_PASSWORD
```

Do **not** copy these example values into production:

```
POSTGRES_PASSWORD=replace-with-your-own-password
BETTER_AUTH_SECRET=replace-with-your-own-secret
OPENROUTER_API_KEY=sk-or-v1-replace-with-your-own-key
```

Open the **Domains** tab in the Coolify service view.

Click:

```
+ Add Domain
```

Configure:

| Setting | Value | 
|---|---|
| Service | `paperclip` | 
| Image | `ghcr.io/paperclipai/paperclip:latest` | 
| Protocol | `https` | 
| Domain | `paperclip.arpann8n.qzz.io` | 
| Port | `3100` | 
| Path | Leave empty | 

Click **Save**.

Coolify/Traefik will use this configuration to route HTTPS traffic to Paperclip's internal port `3100`.

Click **Deploy** in the top-right corner of Coolify.

Coolify should:

After deployment, visit:

```
https://yourDomain.com
```

Because the instance is configured with authenticated public deployment mode, browser-based self-registration is disabled.

A one-time bootstrap link must be generated from inside the Paperclip container.

In Coolify:

```
Observe & troubleshoot
  → Terminal
```

Select the:

```
paperclip
```

container.

Run:

```
chown -R node:node /paperclip
chmod -R 700 /paperclip/instances/default/secrets
```

Then generate the CEO bootstrap URL:

```
su -s /bin/sh node -c "pnpm paperclipai auth bootstrap-ceo"
```

The command should output a single-use URL similar to:

```
https://yourDomain.com/auth/claim?token=...
```

Open that URL in your browser.

Complete the administrator registration:

Treat the bootstrap URL as a credential. Do not post it publicly or commit it to source control.

During the Paperclip onboarding wizard, you may see a screen asking you to connect a model with **Claude** and **OpenAI** buttons.

Those fields may perform provider-specific API validation against Anthropic/OpenAI endpoints. An OpenRouter key is not necessarily valid for those direct-provider checks.

Instead:

```
Use subscription
```

or skip that step if the UI provides a skip option.

Continue through the remaining onboarding steps until you reach the main Paperclip workspace dashboard.

Headless container environments may not provide the terminal capabilities required by some CLI-based agent runtimes.

For this deployment, configure the CEO agent to use an **API-based OpenCode runtime** through OpenRouter.

From the Paperclip workspace:

```
Company name
  → Company Settings
```

Alternatively, navigate to:

```
/company/settings/secrets
+ New secret
```

| Field | Value | 
|---|---|
| Who provides the value? | Organization | 
| Type | Managed value | 
| Name | `OPENROUTER_API_KEY` | 
| Value | Your OpenRouter API key | 
| Key | `OPENROUTER_API_KEY` | 

Your API key will normally look similar to:

```
sk-or-v1-...
```

In the left navigation:

```
Agents
  → CEO
  → Secrets & variables
```

Under:

```
API ACCESS (NO ENV VAR)
```

add:

```
OPENROUTER_API_KEY
Save changes
```

Open the CEO agent settings.

```
Harness / Runtime
```

| Setting | Value | 
|---|---|
| Adapter type | `OpenCode` | 
| Model | Your desired OpenRouter model slug | 

Examples:

```
openai/gpt-4o-mini
anthropic/claude-3.5-sonnet
```

or another model supported by your OpenRouter account and current Paperclip/OpenCode integration.

Model 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.

```
Test again
Verify
```

You should receive a successful connection result.

Then click:

```
Save changes
```

If the CEO agent still shows an old failure banner:

```
Overview
  → Clear error
```

This clears the previous runtime error state after the configuration has been corrected.

```
Tasks
  → Paperclip onboarding (SKO-1)
```

Send a test message such as:

```
Hello, please proceed with the onboarding plan.
```

The CEO agent should process the request through the configured OpenCode runtime and OpenRouter API.

A successful flow should look like:

```
Paperclip Task
      |
      v
CEO Agent
      |
      v
OpenCode Adapter
      |
      v
OpenRouter API
      |
      v
Selected AI Model
      |
      v
Response
      |
      v
Paperclip Task
```

Check DNS:

```
nslookup paperclip.arpann8n.qzz.io
```

Confirm that it resolves to the correct OCI public IP.

Then verify OCI ingress rules allow:

```
TCP 80
TCP 443
```

Also inspect the Ubuntu firewall:

```
sudo iptables -L INPUT -n --line-numbers
```

Check all of the following:

HTTP port 80 can be particularly important when using HTTP-01 certificate validation.

Check the PostgreSQL container:

```
docker ps
```

Inspect logs through Coolify or Docker:

```
docker logs <postgres-container>
```

The PostgreSQL health check is:

```
pg_isready -U paperclip -d paperclip
```

Make sure the application and database use the same:

```
POSTGRES_PASSWORD
```

Inside the Paperclip container, check the volume permissions:

```
ls -la /paperclip
ls -la /paperclip/instances/default
ls -la /paperclip/instances/default/secrets
```

Then run:

```
chown -R node:node /paperclip
chmod -R 700 /paperclip/instances/default/secrets
```

Retry:

```
su -s /bin/sh node -c "pnpm paperclipai auth bootstrap-ceo"
```

If 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.

Check:

```
Agents
  → CEO
  → Harness / Runtime
```

Use:

```
Adapter type: OpenCode
```

and ensure:

```
OPENROUTER_API_KEY
```

is available to the agent.

Verify the secret exists at the company level:

```
Company Settings
  → Secrets
```

Confirm the key is:

```
OPENROUTER_API_KEY
```

Then verify it is bound to:

```
CEO
  → Secrets & variables
```

Do not confuse:

```
OPENROUTER_API_KEY
```

with provider-specific credentials such as:

```
ANTHROPIC_API_KEY
OPENAI_API_KEY
```

Before exposing the deployment to the public internet, review the following.

`POSTGRES_PASSWORD` is strong and unique.`BETTER_AUTH_SECRET` was generated randomly.`5432` is `3100` is 

```
openssl rand -hex 32
openssl rand -base64 32
nslookup paperclip.arpann8n.qzz.io
sudo iptables -L INPUT -n --line-numbers
sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT
sudo netfilter-persistent save
sudo ss -tulpn
```

The complete deployment process is:

```
1. Create OCI ARM64 Ubuntu VPS
           ↓
2. Point DNS A record to VPS
           ↓
3. Allow TCP 80/443 in OCI VCN
           ↓
4. Allow TCP 80/443 on Ubuntu firewall
           ↓
5. Generate BETTER_AUTH_SECRET
           ↓
6. Create Docker Compose stack in Coolify
           ↓
7. Configure PostgreSQL + Paperclip
           ↓
8. Add Coolify environment variables
           ↓
9. Configure Paperclip domain → port 3100
           ↓
10. Deploy stack
           ↓
11. Generate CEO bootstrap URL
           ↓
12. Create administrator account
           ↓
13. Complete onboarding
           ↓
14. Create OPENROUTER_API_KEY secret
           ↓
15. Bind secret to CEO agent
           ↓
16. Configure OpenCode runtime
           ↓
17. Select OpenRouter model
           ↓
18. Verify connection
           ↓
19. Send test task
           ↓
20. Paperclip agent responds through OpenRouter
```

After completing the guide, the deployment should provide:

This 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.

Before production use, verify the current Paperclip and OpenRouter documentation for:

Never expose database credentials, authentication secrets, bootstrap URLs, or API keys in public repositories, screenshots, logs, or issue trackers.
