Stop advertising the stale OpenAPI snapshot as an API catalog. Keep the URL for deploy checks and point agents at MCP.
110 lines
4.8 KiB
Markdown
110 lines
4.8 KiB
Markdown
# Self-hosting and Docker architecture
|
|
|
|
Docker-based self-hosting supports VPS, NAS, and home servers without creating
|
|
a second product implementation. Cloudflare and Docker execute the same Hono
|
|
application and differ only at thin runtime and infrastructure adapter seams.
|
|
|
|
## Current boundary
|
|
|
|
The API's business and route logic must depend on the storage contracts in
|
|
`apps/api/src/storage-contract.ts`, not on a Cloudflare SDK type directly. The
|
|
current concrete implementation lives in
|
|
`apps/api/src/cloudflare-storage-adapter.ts`:
|
|
|
|
- `DatabaseAdapter`: SQL statements and batches.
|
|
- `BlobStoreAdapter`: attachment `get`, `put`, and `delete` operations.
|
|
|
|
Cloudflare injects the D1/R2 adapter into `fetchEdgeEverApp`; the Bun entrypoint
|
|
injects the SQLite/filesystem or SQLite/S3 adapter into that same function.
|
|
Neither entrypoint owns route or business decisions.
|
|
|
|
The shared self-hosted configuration shape is defined as
|
|
`SelfHostedStorageConfig`, with one application data directory, one SQLite
|
|
database file, and one attachment directory.
|
|
|
|
PostgreSQL is reserved as a second relational backend through the
|
|
driver-neutral `RelationalDatabaseAdapter` and `PostgreSQLStorageConfig`
|
|
contracts. It is intentionally not implemented yet. SQLite remains the
|
|
default self-hosted database; PostgreSQL will be useful for larger teams,
|
|
higher write concurrency, and external database operations.
|
|
|
|
## Docker shape
|
|
|
|
The supported container deployment is a single application container with one
|
|
persistent `/data` mount:
|
|
|
|
```text
|
|
EdgeEver container
|
|
├── SQLite database -> /data/edgeever.sqlite
|
|
├── credential secrets -> /data/edgeever-secrets.json
|
|
└── attachment store -> /data/resources
|
|
```
|
|
|
|
The self-hosted adapter preserves the existing SQLite schema and
|
|
`migrations/*.sql` files. Attachments are addressed by the same opaque object
|
|
keys stored in `resources.object_key`; the runtime supports both a local
|
|
filesystem backend and an S3-compatible backend.
|
|
|
|
When PostgreSQL is implemented, it must introduce an explicit SQL dialect and
|
|
migration set for PostgreSQL-specific full-text search and transaction
|
|
behavior. It must not make the current SQLite/D1 migration files silently
|
|
ambiguous.
|
|
|
|
## Compatibility requirements
|
|
|
|
- Keep `/api/*`, `/mcp`, `/api/health`, and the `/api/openapi.json` reachability probe unchanged. `/api/openapi.json` is not an API catalog.
|
|
- Keep the current migration files append-only; do not fork the schema for
|
|
Docker.
|
|
- Keep root secrets in environment variables or Docker secrets, never in the
|
|
image or database. The self-hosted runtime may persist a copy on `/data`
|
|
outside SQLite so NAS/GUI upgrades that drop container environment variables
|
|
keep credential encryption. Cloudflare continues to use Worker secrets only.
|
|
Object-storage secrets and personal AI model API keys use separate
|
|
purpose-specific keys derived from the existing instance authentication
|
|
secret. An optional `EDGE_EVER_CREDENTIALS_ENCRYPTION_KEY` can override the
|
|
AI credential key for advanced rotation. Stored credentials must remain
|
|
AES-GCM ciphertext.
|
|
- Make `/data` the only required persistent application path so NAS users can
|
|
back up one volume.
|
|
- Keep the production entry at `scripts/self-hosted-server.js`, and keep
|
|
`scripts/self-hosted-server.mjs` as an alias for NAS/GUI command overrides
|
|
saved from v1.62 and earlier.
|
|
- Support `EDGE_EVER_AUTH_USERNAME`, `EDGE_EVER_AUTH_PASSWORD`, and session
|
|
settings without Cloudflare-specific naming assumptions in the container
|
|
entrypoint.
|
|
- Keep login brute-force protection in the application layer with SQLite/D1-
|
|
compatible storage; Cloudflare Rate Limiting and WAF may be optional
|
|
deployment-level enhancements, but must not be required.
|
|
- Expose a health check that distinguishes process availability from database
|
|
readiness and attachment-store readiness.
|
|
|
|
Operational instructions, including secrets, HTTPS, backups, upgrades, and NAS
|
|
permissions, live in [Deploy EdgeEver with Docker](deploy-docker.md).
|
|
|
|
The Docker image and local development use the same Bun runtime:
|
|
|
|
```sh
|
|
bun run build:web
|
|
EDGE_EVER_AUTH_PASSWORD='<strong-password>' bun run start:self-hosted
|
|
```
|
|
|
|
Set `EDGE_EVER_DATA_DIR` to the directory that should be persisted by Docker
|
|
or a NAS volume.
|
|
Long-running streaming responses use a 120-second idle timeout by default. Set
|
|
`EDGE_EVER_IDLE_TIMEOUT_SECONDS` to a value from 10 to 255 to override it.
|
|
|
|
The same runtime can use an S3-compatible object store:
|
|
|
|
```sh
|
|
EDGE_EVER_STORAGE_BACKEND=s3 \
|
|
EDGE_EVER_S3_ENDPOINT='http://minio:9000' \
|
|
EDGE_EVER_S3_REGION='us-east-1' \
|
|
EDGE_EVER_S3_BUCKET='edgeever' \
|
|
EDGE_EVER_S3_ACCESS_KEY_ID='<access-key>' \
|
|
EDGE_EVER_S3_SECRET_ACCESS_KEY='<secret-key>' \
|
|
bun run start:self-hosted
|
|
```
|
|
|
|
The implementation uses `@aws-sdk/client-s3` and does not load that SDK in the
|
|
Cloudflare Worker entrypoint.
|