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
38 changes: 38 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Version control
.git
.gitignore

# Python build artefacts
__pycache__
*.py[cod]
*.egg-info
dist/
.venv/
.uv/

# Node build artefacts
ui/node_modules/
ui/.next/
ui/out/

# Generated UI assets (rebuilt inside the Docker build)
src/authsome/ui/web/

# Tests and CI
tests/
.github/
.pre-commit-config.yaml

# Docs and assets
docs/
assets/
*.md
!README.md

# Editor / tooling
.ruff_cache/
.mypy_cache/
.pytest_cache/
.vscode/
.idea/
*.egg
27 changes: 27 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Docker build

on:
push:
branches:
- '**'
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build image
uses: docker/build-push-action@v6
with:
context: .
push: false
tags: authsome:ci
cache-from: type=gha
cache-to: type=gha,mode=max
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Stage 1: Build the Next.js static UI
FROM node:24-slim AS ui-builder
WORKDIR /app
COPY ui/ ./ui/
RUN npm install -g pnpm@10 --silent && \
pnpm --dir ui install --frozen-lockfile && \
pnpm --dir ui build

# Stage 2: Build the Python wheel
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS py-builder
WORKDIR /app
COPY . .
# Inject UI assets built in stage 1 before packaging the wheel
COPY --from=ui-builder /app/ui/out ./ui/out
RUN mkdir -p src/authsome/ui/web && \
cp -R ui/out/. src/authsome/ui/web/ && \
uv build --wheel --out-dir /dist

# Stage 3: Minimal runtime image
FROM python:3.13-slim AS runtime

RUN groupadd -r authsome && \
useradd -r -g authsome -d /home/authsome -m -s /sbin/nologin authsome

COPY --from=py-builder /dist /dist
RUN pip install --no-cache-dir /dist/*.whl && rm -rf /dist

ENV AUTHSOME_HOME=/data/authsome

EXPOSE 7998

VOLUME ["/data/authsome"]

USER authsome

ENTRYPOINT ["authsome", "daemon", "serve"]
CMD ["--host", "0.0.0.0", "--port", "7998"]
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ Requires Python 3.13+.
uv tool install authsome
```

## Self-hosting

Run a persistent daemon in Docker — no Python required on the host:

```bash
docker compose up -d
export AUTHSOME_DAEMON_URL=http://localhost:7998
```

See the [self-hosting guide](docs/guides/self-hosting.md) for volume backup, TLS termination, and environment variable reference.

## Quick Start

Add the authsome skill to your agent (claude, codex, cursor, hermes, etc.):
Expand Down
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:
authsome:
build: .
image: authsome:latest
restart: unless-stopped
ports:
- "7998:7998"
volumes:
- authsome-data:/data/authsome
environment:
AUTHSOME_HOME: /data/authsome
# Set this to the public URL of this server so OAuth callbacks resolve correctly.
# Example: AUTHSOME_SERVER_BASE_URL: https://auth.example.com
AUTHSOME_SERVER_BASE_URL: ""
# Encryption mode: "local_key" (default) or "keyring"
AUTHSOME_ENCRYPTION_MODE: local_key
AUTHSOME_LOG_LEVEL: info
# Uncomment to use a pre-built image from a registry instead of building locally:
# image: ghcr.io/agentrhq/authsome:latest

# ── Optional: Caddy reverse proxy for TLS ─────────────────────────
# Uncomment the block below and add a caddy service to terminate TLS.
# labels:
# caddy: auth.example.com
# caddy.reverse_proxy: "{{upstreams 7998}}"

volumes:
authsome-data:
125 changes: 125 additions & 0 deletions docs/guides/self-hosting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Self-hosting Authsome

Run a persistent Authsome daemon in a container — useful for CI runners, shared agent hosts, or any environment where installing Python tooling is inconvenient.

## Quick start

```bash
# Clone the repo (or copy docker-compose.yml)
git clone https://github.com/agentrhq/authsome.git
cd authsome

# Start the daemon
docker compose up -d

# Verify it's running
curl http://localhost:7998/health
```

The daemon is now available at `http://localhost:7998`.

Point agents at it by setting:

```bash
export AUTHSOME_DAEMON_URL=http://localhost:7998
```

## Environment variables

| Variable | Default | Description |
|---|---|---|
| `AUTHSOME_HOME` | `/data/authsome` | Root directory for credentials, keys, and the database |
| `AUTHSOME_HOST` | `0.0.0.0` | Interface the daemon binds to inside the container |
| `AUTHSOME_PORT` | `7998` | TCP port |
| `AUTHSOME_SERVER_BASE_URL` | _(derived from host:port)_ | Public URL used to build OAuth callback URLs. **Must be set when behind a reverse proxy.** |
| `AUTHSOME_ENCRYPTION_MODE` | `local_key` | `local_key` stores the master key on disk; `keyring` uses the OS keyring (not available in containers) |
| `AUTHSOME_LOG_LEVEL` | `info` | Uvicorn log level (`debug`, `info`, `warning`, `error`) |
| `AUTHSOME_ANALYTICS` | `1` | Set to `0` to disable telemetry |

## Volume

All credentials and keys live at `AUTHSOME_HOME` (`/data/authsome` by default), which is declared as a Docker named volume.

```
/data/authsome/
server/
authsome.db # SQLite database (identities, principals, vaults)
master.key # Vault encryption key — back this up
kv_store/ # Encrypted credential blobs
client/
logs/
```

> **Keep `master.key` safe.** Without it, stored credentials cannot be decrypted.

## Upgrading

```bash
docker compose pull # fetch the latest image
docker compose up -d # restart with zero downtime (data volume is preserved)
```

## Backup and restore

```bash
# Backup
docker run --rm -v authsome-data:/data/authsome -v $(pwd):/backup \
busybox tar czf /backup/authsome-backup.tar.gz -C /data/authsome .

# Restore
docker run --rm -v authsome-data:/data/authsome -v $(pwd):/backup \
busybox tar xzf /backup/authsome-backup.tar.gz -C /data/authsome
```

## TLS with Caddy

Add a Caddy sidecar to the compose file for automatic HTTPS:

```yaml
services:
authsome:
image: authsome:latest
restart: unless-stopped
expose:
- "7998"
environment:
AUTHSOME_SERVER_BASE_URL: https://auth.example.com
volumes:
- authsome-data:/data/authsome

caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
depends_on:
- authsome

volumes:
authsome-data:
caddy-data:
```

`Caddyfile`:

```
auth.example.com {
reverse_proxy authsome:7998
}
```

## Building the image locally

```bash
docker build -t authsome:local .
```

The build is multi-stage:

1. **`ui-builder`** — Node 24 + pnpm compiles the Next.js dashboard to static HTML.
2. **`py-builder`** — uv bundles the Python package (including the built UI) into a wheel.
3. **`runtime`** — Slim Python 3.13 image; installs the wheel, runs as a non-root `authsome` user.
Loading