Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions arc-paste/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Caddyfile — TLS termination + reverse proxy for arc-paste.
#
# Mounted read-only at /etc/caddy/Caddyfile by compose.yaml. Caddy reads this
# automatically on startup, so the compose service has no `command:` block.
#
# To change the public hostname, edit the site address below. To change the
# ACME contact, edit `email` in the global block. Reload without downtime via:
# docker compose -f arc-paste/compose.yaml exec caddy caddy reload --config /etc/caddy/Caddyfile

{
# Let's Encrypt sends expiry + revocation notices here. Without it, you
# only learn about cert problems when the site goes down.
email ops@company.com
}

arcpaste.company.com {
# Negotiate compression with the client. zstd preferred, gzip fallback.
encode zstd gzip

# arc-paste listens on the internal Docker network — the service name
# resolves via Compose's embedded DNS.
reverse_proxy arc-paste:7433

# Structured access logs to stdout so `docker compose logs caddy`
# stays parseable by jq / log shippers.
log {
output stdout
format json
}
}
35 changes: 32 additions & 3 deletions arc-paste/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
# Stop:
# docker compose -f arc-paste/compose.yaml down
#
# Caddy terminates HTTPS for arcpaste.company.com. Make sure DNS points to this
# host and inbound ports 80/443 are reachable for Let's Encrypt certificate
# issuance and renewal.
#
# The Dockerfile lives in arc-paste/ but builds from the repo root because it
# needs the parent Go module — that's what `context: ..` below selects.

Expand All @@ -17,8 +21,8 @@ services:
dockerfile: arc-paste/Dockerfile
image: arc-paste:latest
container_name: arc-paste
ports:
- "7433:7433"
expose:
- "7433"
volumes:
# Named volume keeps the SQLite db across container rebuilds.
# arc-paste creates the directory itself on startup, so a fresh
Expand All @@ -33,8 +37,33 @@ services:
# No healthcheck: the runtime image is `scratch`, which has no shell,
# wget, curl, or anything else compose's `healthcheck.test` could exec.
# For production monitoring, run an external probe (Cloudflare health
# check, Uptime Kuma, etc.) against the host port instead.
# check, Uptime Kuma, etc.) against the Caddy HTTPS endpoint instead.

caddy:
# Pin minor version for reproducible deploys; bump deliberately when you
# want new features. Floating `:2-alpine` would silently follow upstream.
image: caddy:2.11-alpine
container_name: arc-paste-caddy
depends_on:
- arc-paste
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
# Caddyfile drives the reverse proxy + ACME config. Mounted read-only
# so the container can't accidentally rewrite it on `caddy reload`.
- ./Caddyfile:/etc/caddy/Caddyfile:ro
# Persist ACME certificates and Caddy autosave config across restarts.
# Losing /data means losing the ACME account + certs — risks LE rate limits.
- caddy-data:/data
- caddy-config:/config
restart: unless-stopped

volumes:
arc-paste-data:
name: arc-paste-data
caddy-data:
name: arc-paste-caddy-data
caddy-config:
name: arc-paste-caddy-config
21 changes: 15 additions & 6 deletions docs/runbooks/paste-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,30 @@ Remote mode runs the standalone `arc-paste` binary (a thin wrapper around the sa
ARC_PASTE_ADDR=:7433 ARC_PASTE_DB=/tmp/arc-paste.db ./bin/arc-paste
```

Or via Docker (uses the `arc-paste/Dockerfile` scratch image and a named volume):
Or via Docker for the production-style HTTPS stack (uses the `arc-paste/Dockerfile` scratch image, a named SQLite volume, and Caddy for `https://arcpaste.company.com`):

```bash
docker compose -f arc-paste/compose.yaml up -d --build
docker compose -f arc-paste/compose.yaml logs -f
```

The compose file binds host port 7433, persists SQLite to the `arc-paste-data` named volume, and sets `restart: unless-stopped`. Note: the runtime image is `scratch`, so there's no in-container healthcheck — pair with an external probe (Cloudflare health check, Uptime Kuma, etc.) for production.
The compose file publishes Caddy on host ports 80/443 (including UDP 443 for HTTP/3), exposes `arc-paste` only on the internal Docker network, persists SQLite to the `arc-paste-data` named volume, persists Caddy certificate state to named volumes, and sets `restart: unless-stopped`. Caddy is configured via `arc-paste/Caddyfile` (mounted read-only) — edit the site address there to change the public hostname, or `email` in the global block to change the ACME contact. After editing, reload without downtime:

### Create a shared paste pointed at the standalone server
```bash
docker compose -f arc-paste/compose.yaml exec caddy caddy reload --config /etc/caddy/Caddyfile
```

Make sure DNS for `arcpaste.company.com` points to the host and ports 80/443 are reachable for Let's Encrypt issuance and renewal. Note: the runtime image is `scratch`, so there's no in-container healthcheck — pair with an external probe (Cloudflare health check, Uptime Kuma, etc.) against the HTTPS endpoint for production.

### Create a shared paste pointed at the remote server

```bash
# Terminal 2
./bin/arc share create /tmp/test-plan.md --share --server http://localhost:7433
# → Share URL: http://localhost:7433/share/<id>#k=<key>
# Terminal 2 (Docker/Caddy stack)
./bin/arc share create /tmp/test-plan.md --share --server https://arcpaste.company.com
# → Share URL: https://arcpaste.company.com/share/<id>#k=<key>

# If you launched the standalone binary directly instead, use:
# ./bin/arc share create /tmp/test-plan.md --share --server http://localhost:7433
```

That URL is what you'd send to a real reviewer (Slack, email, etc.). It contains everything they need: the share id and the decryption key in the fragment.
Expand Down
Loading