Self-hosted HTTP cache server for Polykit remote caching.
Features: Self-hosted, single binary, content-addressed storage, directory sharding, atomic operations, integrity verification, streaming I/O, graceful shutdown.
Installation
Install from crates.io (recommended):
Or build from source:
Binary: target/release/polykit-cache
Usage
Starting the Server
Basic usage with defaults (port 8080, ./cache storage):
Configuration Options
Options:
--storage-dir: Directory for artifact storage (default:./cache)--max-size: Maximum artifact size in bytes (default: 1GB)--bind: Bind address (default:127.0.0.1)--port: Port number (default:8080)--log-level: Log level - trace, debug, info, warn, error (default:info)
Client Configuration
CLI: polykit build --remote-cache-url http://localhost:8080
Config file (polykit.toml):
[]
= "http://localhost:8080"
Deployment
Docker
Build:
Or use docker-compose:
Systemd Service
Create /etc/systemd/system/polykit-cache.service:
[Unit]
Description=Polykit Cache Server
After=network.target
[Service]
Type=simple
User=polykit
Group=polykit
ExecStart=/usr/local/bin/polykit-cache \
--storage-dir /var/cache/polykit \
--bind 0.0.0.0 \
--port 8080 \
--log-level info
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start:
Reverse Proxy (Nginx)
For production deployments, use a reverse proxy:
upstream polykit_cache {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name cache.example.com;
client_max_body_size 1G;
location / {
proxy_pass http://polykit_cache;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
API
Upload Artifact
PUT /v1/artifacts/{cache_key}
Content-Type: application/octet-stream
<zstd-compressed artifact data>
Response:
201 Created- Upload successful400 Bad Request- Invalid cache key format409 Conflict- Artifact already exists413 Payload Too Large- Artifact exceeds size limit422 Unprocessable Entity- Verification failed
Download Artifact
GET /v1/artifacts/{cache_key}
Response:
200 OK- Returns compressed artifact with headers:Content-Type: application/zstdContent-Length: <size>X-Artifact-Hash: <sha256>
404 Not Found- Artifact does not exist
Check Artifact Existence
HEAD /v1/artifacts/{cache_key}
Response:
200 OK- Artifact exists (includes same headers as GET)404 Not Found- Artifact does not exist
Storage Layout
Artifacts are stored with directory sharding:
<storage-dir>/
aa/
bb/
<cache_key>.zst # Compressed artifact
<cache_key>.json # Metadata
The first 4 characters of the cache key determine the directory structure (aa/bb/).
Security
No built-in auth - Deploy behind firewall/VPN or use reverse proxy (Nginx/Caddy) with TLS and auth.
Storage limits - Set --max-size to prevent exhaustion. Run as dedicated user with restricted permissions.
Monitoring
Logs to stdout. Monitor uploads/downloads, verification failures, storage errors, shutdown signals. Integrate with journald, fluentd, or Loki.
Performance
Concurrent uploads - No global locks, scales with CPU cores. Streaming - No full buffering. Atomic writes - Temp file + rename. Directory sharding - Prevents filesystem slowdowns.
License
See LICENSE.md in the repository root.