Appearance
Bare Metal Deployment
This guide installs Agentcy directly on a Linux server with no container runtime. It is suitable for:
- Air-gapped or restricted networks where Docker is not allowed
- Long-lived single-server deployments where simplicity beats portability
- Environments with existing Postgres / Redis / Neo4j you want to reuse
For most teams, Docker Compose is simpler. Choose bare metal only if you have a clear reason.
Architecture
Every component runs as a systemd unit on the same Linux host. Reverse proxy fronts the two app processes; databases listen on 127.0.0.1 only.
Target Topology
A single Linux host running:
| Component | How it runs | Port |
|---|---|---|
agentcy-api | systemd service, static binary | 8080 |
agentcy-frontend | systemd service, node server.js | 3000 |
| PostgreSQL 16 | OS package | 5432 |
| Neo4j 5 Community | OS package or tarball | 7687 |
| Redis 7 | OS package | 6379 |
| Caddy / Nginx | OS package | 80 / 443 |
Prerequisites
Tested on Ubuntu 22.04 / 24.04 and Debian 12. Other distros work — adapt package names.
bash
sudo apt-get update
sudo apt-get install -y curl ca-certificates gnupg lsb-release \
postgresql-16 postgresql-contrib redis-server caddy nodejs npm1
2
3
2
3
For Neo4j 5:
bash
curl -fsSL https://debian.neo4j.com/neotechnology.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/neo4j.gpg
echo "deb [signed-by=/usr/share/keyrings/neo4j.gpg] https://debian.neo4j.com stable 5" | \
sudo tee /etc/apt/sources.list.d/neo4j.list
sudo apt-get update
sudo apt-get install -y neo4j1
2
3
4
5
2
3
4
5
glibc match
The published agentcy-api binaries are compiled against glibc 2.35 (Ubuntu 22.04). Older distros need either a custom build or the Docker option.
Install Agentcy Binaries
Self-host customers receive a release tarball. It contains:
agentcy-<version>/
├── bin/agentcy-api # Rust API server
├── frontend/ # Next.js standalone build
├── migrations/ # Reference SQL (already embedded in binary)
└── systemd/ # Sample unit files1
2
3
4
5
2
3
4
5
Copy the binaries:
bash
sudo useradd --system --home /opt/agentcy --shell /usr/sbin/nologin agentcy
sudo mkdir -p /opt/agentcy/{bin,frontend,etc,logs}
sudo cp agentcy-<version>/bin/agentcy-api /opt/agentcy/bin/
sudo cp -r agentcy-<version>/frontend/* /opt/agentcy/frontend/
sudo chown -R agentcy:agentcy /opt/agentcy1
2
3
4
5
2
3
4
5
Configure Databases
PostgreSQL
bash
sudo -u postgres psql <<'SQL'
CREATE USER agentcy WITH PASSWORD 'replace-me';
CREATE DATABASE agentcy OWNER agentcy;
GRANT ALL PRIVILEGES ON DATABASE agentcy TO agentcy;
\c agentcy
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
SQL1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
The vector extension is shipped by pgvector — install it via sudo apt-get install postgresql-16-pgvector.
Neo4j
bash
sudo neo4j-admin dbms set-initial-password 'replace-me'
sudo systemctl enable --now neo4j1
2
2
Edit /etc/neo4j/neo4j.conf:
server.default_listen_address=127.0.0.1
server.bolt.listen_address=:7687
server.memory.heap.max_size=2G
server.memory.pagecache.size=1G1
2
3
4
2
3
4
Context Engine — Advanced (optional, instead of Neo4j)
If you want KQL/SQL/time-series and OTLP-native ingest on bare metal, run kyma instead of (or alongside) Neo4j. Single-binary mode is fine for one host:
bash
sudo curl -fsSL https://github.com/agentcylabs/kyma/releases/latest/download/kyma-linux-amd64 \
-o /opt/agentcy/bin/kyma
sudo chmod +x /opt/agentcy/bin/kyma1
2
3
2
3
For object storage on a single host, use MinIO — install it as a systemd unit pointed at /var/lib/kyma/data. kyma's catalog can live in the same Postgres instance under a separate database (CREATE DATABASE kyma_catalog OWNER agentcy;).
Sample systemd unit (/etc/systemd/system/kyma.service):
ini
[Unit]
Description=kyma context engine
After=network.target postgresql.service minio.service
[Service]
Type=simple
User=agentcy
Environment=KYMA_BASE_URL=http://127.0.0.1:8080
Environment=KYMA_OBJECT_STORE_URL=s3://kyma-extents
Environment=AWS_ENDPOINT_URL=http://127.0.0.1:9000
Environment=KYMA_CATALOG_DATABASE_URL=postgres://agentcy:replace-me@127.0.0.1:5432/kyma_catalog
ExecStart=/opt/agentcy/bin/kyma serve
Restart=always
[Install]
WantedBy=multi-user.target1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Then in /opt/agentcy/etc/agentcy.env swap the Neo4j vars for:
bash
CONTEXT_ENGINE=advanced
KYMA_BASE_URL=http://127.0.0.1:8080
KYMA_TOKEN=replace-me
KYMA_DATABASE=kyma1
2
3
4
2
3
4
Redis
The default install on 127.0.0.1:6379 is fine. Enable persistence:
bash
sudo sed -i 's/^# save .*/save 60 1000/' /etc/redis/redis.conf
sudo sed -i 's/^appendonly no/appendonly yes/' /etc/redis/redis.conf
sudo systemctl restart redis-server1
2
3
2
3
Configure Agentcy
Create /opt/agentcy/etc/agentcy.env:
bash
# Databases
DATABASE_URL=postgres://agentcy:replace-me@127.0.0.1:5432/agentcy
NEO4J_URI=bolt://127.0.0.1:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=replace-me
REDIS_URL=redis://127.0.0.1:6379
# LLM
LLM_PROVIDER=anthropic
LLM_API_KEY=sk-ant-...
# Auth
AUTH_PROVIDER=local
JWT_SECRET=$(openssl rand -hex 32)
# HTTP
BIND_ADDR=127.0.0.1:8080
CORS_ORIGINS=https://agentcy.example.com
LOG_LEVEL=info1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Lock it down — it contains secrets:
bash
sudo chown agentcy:agentcy /opt/agentcy/etc/agentcy.env
sudo chmod 600 /opt/agentcy/etc/agentcy.env1
2
2
Systemd Units
/etc/systemd/system/agentcy-api.service:
ini
[Unit]
Description=Agentcy API
After=network.target postgresql.service neo4j.service redis-server.service
Requires=postgresql.service neo4j.service redis-server.service
[Service]
Type=simple
User=agentcy
Group=agentcy
EnvironmentFile=/opt/agentcy/etc/agentcy.env
ExecStart=/opt/agentcy/bin/agentcy-api
Restart=always
RestartSec=5
LimitNOFILE=65536
StandardOutput=append:/opt/agentcy/logs/api.log
StandardError=append:/opt/agentcy/logs/api.log
# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/opt/agentcy/logs
[Install]
WantedBy=multi-user.target1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/etc/systemd/system/agentcy-frontend.service:
ini
[Unit]
Description=Agentcy Frontend
After=network.target agentcy-api.service
[Service]
Type=simple
User=agentcy
Group=agentcy
WorkingDirectory=/opt/agentcy/frontend
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=NEXT_PUBLIC_API_URL=https://agentcy.example.com/api/v1
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=5
StandardOutput=append:/opt/agentcy/logs/frontend.log
StandardError=append:/opt/agentcy/logs/frontend.log
[Install]
WantedBy=multi-user.target1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Start everything:
bash
sudo systemctl daemon-reload
sudo systemctl enable --now agentcy-api agentcy-frontend
sudo systemctl status agentcy-api1
2
3
2
3
Reverse Proxy with Caddy
/etc/caddy/Caddyfile:
agentcy.example.com {
encode gzip zstd
handle /api/* {
reverse_proxy 127.0.0.1:8080
}
handle {
reverse_proxy 127.0.0.1:3000
}
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
bash
sudo systemctl reload caddy1
Caddy fetches a Let's Encrypt cert automatically.
Backups
Schedule nightly dumps via cron or a systemd timer.
/etc/cron.daily/agentcy-backup:
bash
#!/bin/bash
set -euo pipefail
DATE=$(date +%F)
DIR=/var/backups/agentcy/$DATE
mkdir -p "$DIR"
# Postgres
sudo -u postgres pg_dump agentcy | gzip > "$DIR/postgres.sql.gz"
# Neo4j (online backup; community edition supports dump)
sudo -u neo4j neo4j-admin database dump neo4j --to-path="$DIR"
# Retain 14 days
find /var/backups/agentcy -maxdepth 1 -type d -mtime +14 -exec rm -rf {} +1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
bash
sudo chmod +x /etc/cron.daily/agentcy-backup1
Updating
- Stop services:
sudo systemctl stop agentcy-frontend agentcy-api - Backup (see above).
- Replace
/opt/agentcy/bin/agentcy-apiand/opt/agentcy/frontend/from the new release tarball. - Start:
sudo systemctl start agentcy-api agentcy-frontend. Migrations run on boot.
Troubleshooting
agentcy-api exits immediately
Check /opt/agentcy/logs/api.log. The most common causes are wrong DATABASE_URL, missing pgvector extension, or Neo4j refusing connections.
High Neo4j memory usage
The pagecache setting in neo4j.conf lets the OS hand pages back. On smaller hosts, drop heap to 1G and pagecache to 512m.
Frontend 502 errors
Confirm NEXT_PUBLIC_API_URL is set to the public URL the browser will reach (not localhost), and that CORS_ORIGINS on the API matches the frontend's origin.
Next Steps
- Environment Variables — full reference
- API Keys — issue scoped tokens
- Audit Log — track everything