Add Clay agent interface, fix registry UI routing, and misc improvements
- Deploy Clay (claude Code web UI) at agent.ladkau.de behind basic auth; Traefik proxies to clay's HTTPS port 2633 with insecureSkipVerify - Document MCP server persistence: binaries need to be baked into the Dockerfile, config in /opt/clay/data survives rebuilds - Document scheduled agent workflows via Gitea Actions on.schedule with email reporting via Gmail SMTP - Fix registry UI: split /v2/ (registry) and / (UI) into separate Traefik routers; add registry_internal network - Add weekly registry GC cron job (/usr/local/bin/registry-gc) - Remove rate-limit middleware from Gitea router (act_runner polling exceeded 60 req/min limit) - Set Traefik websecure readTimeout: 0 to fix large layer upload 499s
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
# Claude Code needs git and bash to operate on repositories
|
||||
RUN apk add --no-cache git bash curl
|
||||
|
||||
# Install Claude Code CLI
|
||||
RUN npm install -g @anthropic-ai/claude-code
|
||||
|
||||
# Install clay web server
|
||||
RUN npm install -g clay-server
|
||||
|
||||
# MCP servers and skills — add packages here to survive container rebuilds
|
||||
# RUN npm install -g @clay-ai/clay-ralph
|
||||
# RUN npm install -g @modelcontextprotocol/server-filesystem
|
||||
|
||||
RUN mkdir -p /workspace /root/.clay
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
EXPOSE 2633
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Rebuild and restart clay
|
||||
community.docker.docker_image:
|
||||
name: clay:local
|
||||
build:
|
||||
path: "{{ clay_data_dir }}"
|
||||
source: build
|
||||
force_source: true
|
||||
state: present
|
||||
notify: Restart clay
|
||||
|
||||
- name: Restart clay
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ clay_data_dir }}"
|
||||
state: present
|
||||
recreate: always
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
- name: Create clay directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ clay_data_dir }}"
|
||||
- "{{ clay_data_dir }}/data"
|
||||
- "{{ clay_data_dir }}/workspace"
|
||||
tags: clay
|
||||
|
||||
- name: Deploy Dockerfile
|
||||
ansible.builtin.copy:
|
||||
src: Dockerfile
|
||||
dest: "{{ clay_data_dir }}/Dockerfile"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Rebuild and restart clay
|
||||
tags: clay
|
||||
|
||||
- name: Deploy Docker Compose file
|
||||
ansible.builtin.template:
|
||||
src: docker-compose.yml.j2
|
||||
dest: "{{ clay_data_dir }}/docker-compose.yml"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Restart clay
|
||||
tags: clay
|
||||
|
||||
- name: Build clay image
|
||||
community.docker.docker_image:
|
||||
name: clay:local
|
||||
build:
|
||||
path: "{{ clay_data_dir }}"
|
||||
source: build
|
||||
state: present
|
||||
tags: clay
|
||||
|
||||
- name: Start clay
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ clay_data_dir }}"
|
||||
state: present
|
||||
tags: clay
|
||||
@@ -0,0 +1,35 @@
|
||||
# Managed by Ansible — do not edit manually
|
||||
services:
|
||||
clay:
|
||||
image: clay:local
|
||||
build:
|
||||
context: {{ clay_data_dir }}
|
||||
dockerfile: Dockerfile
|
||||
container_name: clay
|
||||
restart: unless-stopped
|
||||
tty: true
|
||||
environment:
|
||||
- ANTHROPIC_API_KEY={{ anthropic_api_key }}
|
||||
volumes:
|
||||
- {{ clay_data_dir }}/data:/root/.clay
|
||||
- {{ clay_data_dir }}/workspace:/workspace
|
||||
command: ["clay-server", "--yes", "-p", "2633"]
|
||||
networks:
|
||||
- traefik_public
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.clay.rule=Host(`{{ domain_clay }}`)"
|
||||
- "traefik.http.routers.clay.entrypoints=websecure"
|
||||
- "traefik.http.routers.clay.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.clay.loadbalancer.server.scheme=https"
|
||||
- "traefik.http.services.clay.loadbalancer.server.port=2633"
|
||||
- "traefik.http.routers.clay.middlewares=clay-auth"
|
||||
{% set ns = namespace(entries=[]) %}
|
||||
{% for user in clay_users %}
|
||||
{% set ns.entries = ns.entries + [user.username + ':' + (user.password | password_hash('bcrypt', (user.username | hash('md5'))[:22]) | replace('$', '$$'))] %}
|
||||
{% endfor %}
|
||||
- "traefik.http.middlewares.clay-auth.basicauth.users={{ ns.entries | join(',') }}"
|
||||
|
||||
networks:
|
||||
traefik_public:
|
||||
external: true
|
||||
@@ -25,6 +25,7 @@ SERVICES = [
|
||||
("k8s", "https://{{ domain_k8s }}", 200, "https://{{ domain_k8s }}"),
|
||||
("Vaultwarden", "https://{{ domain_vault }}", 200, "https://{{ domain_vault }}"),
|
||||
("Downloads", "https://{{ domain_dl }}", 200, "https://{{ domain_dl }}"),
|
||||
("Clay", "https://{{ domain_clay }}", 401, "https://{{ domain_clay }}"),
|
||||
]
|
||||
{% raw %}
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ entryPoints:
|
||||
imaps:
|
||||
address: ":993"
|
||||
|
||||
serversTransport:
|
||||
insecureSkipVerify: true # allows Traefik to proxy clay's self-signed d.clay.studio cert on port 2633
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
|
||||
Reference in New Issue
Block a user