Production Deployment¶
Docker Compose — Development¶
The default setup is designed for local development:
Tip
Drop the -d flag to run in the foreground and see logs in real time. Press Ctrl+C to stop the server.
This starts Arca with:
- Auto-generated or environment-provided credentials
- Data stored in a Docker volume (
arca-data) - Port 9000 exposed to localhost
Docker Compose — Production¶
For production, customize the configuration and use persistent storage.
1. Create a Config File¶
[server]
bind = "0.0.0.0"
port = 9000
# domain = "s3.example.com" # uncomment for virtual-hosted-style
[storage]
data_dir = "/data"
blob_prefix_depth = 2
2. Docker Compose File¶
services:
arca:
image: arca
build:
context: .
dockerfile: docker/Dockerfile
target: production
ports:
- "9000:9000"
volumes:
- /srv/arca/data:/data
- ./config/production.toml:/etc/arca/config.toml:ro
environment:
- ARCA_LOG=info
restart: unless-stopped
Warning
Do not set ARCA_ROOT_ACCESS_KEY / ARCA_ROOT_SECRET_KEY in production. Let Arca generate credentials on first startup, then manage them via arca credential CLI commands.
3. First Startup¶
Store the generated credentials securely. They are shown only once.
4. Add Application Credentials¶
Create non-admin credentials for application access:
docker compose exec arca arca credential add --description "web app"
docker compose exec arca arca credential add --description "backup service"
Reserve admin credentials for the web console and administrative tasks.
Native TLS¶
Arca supports native HTTPS without a reverse proxy. See the TLS guide for full details.
Quick Setup¶
Place your certificate and key PEM files in the certs/ directory, then:
The --tls flag adds the TLS compose overlay which bind-mounts certs/ into the container and enables auto-detection of PEM files. This works with any certificate provider (Let's Encrypt, internal CA, etc.) — just drop the PEM files in the directory.
Certificate rotation is supported via docker compose kill --signal=HUP arca without downtime.
Native Binary (systemd)¶
Arca can run directly on a Linux host without Docker. The binary is statically linked (musl), so it has no runtime dependencies.
1. Install the Binary¶
Build for your target architecture and copy to the host:
# Build from source (requires Docker on the build machine)
bin/build --binary # native arch
bin/build --binary --arch amd64 # cross-compile for x86_64
# Copy to the server
scp build/arca-* server:/usr/local/bin/arca
chmod +x /usr/local/bin/arca
2. Create User and Directories¶
useradd --system --home-dir /var/lib/arca --shell /usr/sbin/nologin arca
mkdir -p /var/lib/arca /etc/arca
chown arca:arca /var/lib/arca
3. Configuration¶
Copy the sample config and adjust it:
At minimum, review [server] bind/port and [storage] data_dir (set to /var/lib/arca for systemd deployments). See the configuration reference for all options.
4. Install the systemd Unit¶
cp deploy/systemd/arca.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now arca
Check startup and first-run credentials:
Tip
The systemd unit includes security hardening (sandboxed filesystem, no new privileges, private /tmp). It also sets TimeoutStopSec=45 to allow in-flight requests to complete during graceful shutdown.
5. TLS with systemd¶
To enable native TLS:
Uncomment the [server.tls] section in /etc/arca/config.toml and set the paths. To rotate certificates without downtime:
Kubernetes¶
Arca Server¶
Arca runs well in Kubernetes as a Deployment (stateless, with a PersistentVolumeClaim for data) or as a StatefulSet. Key considerations:
- Mount a PVC at the
data_dirpath (default/data) - Use a
ConfigMapor mountedSecretfor/etc/arca/config.toml - The
/admin/healthendpoint returns200when healthy and503when draining, use it for both liveness and readiness probes - Set
drain_timeout_secondsto match or exceed your pod termination grace period - For PostgreSQL metadata backend, use an external database (RDS, CloudNative-PG, etc.)
livenessProbe:
httpGet:
path: /admin/health
port: 9000
initialDelaySeconds: 5
periodSeconds: 30
readinessProbe:
httpGet:
path: /admin/health
port: 9000
initialDelaySeconds: 2
periodSeconds: 10
Arca Console¶
A ready-to-use Kubernetes manifest is provided at deploy/kubernetes/arca-console.yaml with Deployment, Service, and Ingress resources.
# Replace the namespace placeholder and apply
sed 's/NAMESPACE/arca/g' deploy/kubernetes/arca-console.yaml | kubectl apply -f -
# Or apply to a specific namespace directly
kubectl apply -f deploy/kubernetes/arca-console.yaml -n arca
Customize before applying:
| Placeholder / Setting | Description |
|---|---|
NAMESPACE |
Target Kubernetes namespace |
image: arca-console:latest |
Your container registry and tag |
ARCA_ENDPOINT |
URL of the Arca server (e.g. http://arca:9000 for in-cluster) |
host: console.example.com |
Ingress hostname for the console |
ingressClassName |
Your ingress controller class (uncomment) |
tls |
TLS termination at the ingress (uncomment and configure) |
Note
The console is a lightweight nginx SPA, resource requests are minimal (50m CPU, 32Mi RAM). Scale replicas as needed for availability.
Reverse Proxy¶
If you prefer external TLS termination, or need additional proxy-level features, place a reverse proxy in front of Arca.
Note
With native TLS, built-in rate limiting, and metadata caching available natively, a reverse proxy is optional. Use it when you need features like geographic load balancing or WAF integration.
nginx Example¶
server {
listen 443 ssl;
server_name s3.example.com;
ssl_certificate /etc/ssl/certs/s3.example.com.pem;
ssl_certificate_key /etc/ssl/private/s3.example.com.key;
client_max_body_size 0; # unlimited — Arca handles streaming
location / {
proxy_pass http://arca:9000;
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;
# Required for streaming uploads
proxy_request_buffering off;
proxy_http_version 1.1;
}
}
Tip
Set client_max_body_size 0 and proxy_request_buffering off to allow Arca's streaming I/O to work correctly with large objects.
Rate Limiting¶
Arca has built-in rate limiting to protect against abuse and resource exhaustion. Both per-IP and per-credential limiters are available, using the GCRA (Generic Cell Rate Algorithm) for smooth rate enforcement.
[server.limits]
rate_limit_per_ip_per_second = 500 # per client IP
rate_limit_per_ip_burst = 1000
rate_limit_per_second = 100 # per S3 credential
rate_limit_burst = 200
When a limit is exceeded, the server returns HTTP 503 with S3 error code SlowDown and a Retry-After: 1 header. AWS SDKs and most S3 clients handle this automatically with exponential backoff.
Rate limiting is disabled by default (rate = 0). Enable it for any deployment exposed to the internet or shared by multiple tenants. See the configuration reference for all settings.
Tip
Behind a reverse proxy, per-IP limiting uses the X-Forwarded-For header (first entry) to identify clients. Make sure your proxy sets this header.
Graceful Shutdown¶
On SIGTERM or SIGINT, Arca enters drain mode:
- The
/admin/healthendpoint immediately starts returning503 {"status":"draining"} - Load balancers polling health stop routing new traffic to the instance
- In-flight requests are allowed to complete during the drain window
- After
drain_timeout_seconds(default: 30), the server shuts down
This enables zero-downtime rolling upgrades in orchestrated environments (Kubernetes, Docker Swarm, etc.). Set the drain timeout to match or exceed your load balancer's health check interval.
Metadata Cache¶
Arca caches frequently-accessed metadata (bucket existence, object HEAD results) in an in-memory LRU cache to reduce SQLite query pressure under load.
[server.cache]
enabled = true
bucket_cache_size = 1000
bucket_cache_ttl_seconds = 60
object_cache_size = 10000
object_cache_ttl_seconds = 30
The cache is enabled by default and transparent to clients. Write operations invalidate the corresponding cache entry immediately. TTL provides a safety net for eventual expiry.
For single-node deployments, the cache is purely a performance optimization. Disable it (enabled = false) if you need to minimize memory usage. See the configuration reference for all settings.
Storage Sizing¶
Blob Prefix Depth¶
The blob_prefix_depth setting controls how blob files are distributed across directories:
| Depth | Leaf directories | Files/dir (at 100M objects) | Recommended for |
|---|---|---|---|
| 1 | 256 | ~390,000 | Tiny deployments (<100K objects) |
| 2 | 65,536 | ~1,525 | Most deployments (default) |
| 3 | 16.7M | ~6 | Very large (>10M objects) |
The default depth of 2 works well for most deployments. Only increase it if you expect tens of millions of objects and observe filesystem performance issues.
Disk Space¶
Arca stores each object as a blob file plus a small .meta sidecar (typically <1 KB). Plan for:
- Object data: sum of all stored object sizes
- Sidecar overhead: ~500 bytes per object
- SQLite database: ~1 KB per object record
- Temporary files during multipart uploads
Security Hardening¶
Request Validation¶
Arca validates incoming requests to reject malformed or oversized payloads early in the middleware stack:
- Body size limit — requests exceeding
max_body_size(default 5 GB) are rejected withEntityTooLargebefore data is written to disk - Header count limit — requests with more than
max_header_count(default 100) headers are rejected - Metadata size limit — total
x-amz-meta-*header size is capped atmax_metadata_size(default 2 KB), matching S3's limit - URI validation — null bytes in request URIs are rejected
All limits are configurable via [server.limits]. See the configuration reference.
Credential Management¶
- Disable environment overrides — do not set
ARCA_ROOT_ACCESS_KEY/ARCA_ROOT_SECRET_KEYin production - Use non-admin credentials for applications — admin credentials should only be used for the web console and administrative tasks
- Rotate credentials periodically — create new credentials and remove old ones via
arca credential
Network Isolation¶
- Run Arca on an internal network, exposed only through a reverse proxy
- Use firewall rules to restrict access to port 9000
- Place the web console behind authentication if exposing it externally
Filesystem Permissions¶
- The data directory should be owned by the Arca process user
- Use read-only mounts for the config file (
:roin Docker) - Back up the data directory regularly (see Disaster Recovery)