chore: initialize

This commit is contained in:
Ray Andrew 2026-02-13 00:10:01 -06:00
commit f202a39e52
Signed by: rayandrew
SSH key fingerprint: SHA256:EUCV+qCSqkap8rR+p+zGjxHfKI06G0GJKgo1DIOniQY
6 changed files with 301 additions and 0 deletions

27
.env.example Normal file
View file

@ -0,0 +1,27 @@
# ============================================
# Hetzner Self-Hosted Stack — Environment Variables
# Copy to .env and fill in your values:
# cp .env.example .env
# ============================================
# --- LiteLLM ---
LITELLM_MASTER_KEY=sk-change-me-to-a-random-string
OPENROUTER_API_KEY=sk-or-...
SILICONFLOW_API_KEY=sk-...
DEEPINFRA_API_KEY=...
GROQ_API_KEY=gsk_...
CEREBRAS_API_KEY=...
# --- Cloudflare Tunnel ---
# Create a tunnel in Cloudflare Zero Trust dashboard → Networks → Tunnels
# Copy the token from the tunnel install command
CLOUDFLARE_TUNNEL_TOKEN=eyJ...
# --- Tailscale ---
# Generate at https://login.tailscale.com/admin/settings/keys
# Use a reusable + ephemeral key for unattended servers
TS_AUTHKEY=tskey-auth-...
# --- SearXNG ---
# Random secret key for SearXNG (generate with: openssl rand -hex 32)
SEARXNG_SECRET_KEY=change-me-to-a-random-hex-string

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
# Environment secrets
.env
# SearXNG runtime state
searxng/uwsgi.ini

31
cloud-init.yml Normal file
View file

@ -0,0 +1,31 @@
#cloud-config
users:
- name: rayandrew
groups: [sudo, docker]
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ssh-import-id gh:rayandrew
package_update: true
package_upgrade: true
packages:
- curl
- git
- unattended-upgrades
runcmd:
# Install Docker via official convenience script
- curl -fsSL https://get.docker.com | sh
- systemctl enable docker
- systemctl start docker
# Clone repo and set ownership
- git clone https://git.rs.ht/rayandrew/ai-servers.git /home/rayandrew/ai-servers
- chown -R rayandrew:rayandrew /home/rayandrew/ai-servers
# Enable automatic security updates
- systemctl enable unattended-upgrades
- systemctl start unattended-upgrades

122
docker-compose.yml Normal file
View file

@ -0,0 +1,122 @@
services:
# ── Cache for SearXNG ──
valkey:
image: valkey/valkey:8-alpine
command: valkey-server --save 30 1 --loglevel warning
volumes:
- valkey-data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# ── Private search engine ──
searxng:
image: searxng/searxng:latest
volumes:
- ./searxng:/etc/searxng:rw
environment:
- SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY}
ports:
- "127.0.0.1:8080:8080"
depends_on:
valkey:
condition: service_healthy
restart: unless-stopped
# ── Vector database ──
chromadb:
image: chromadb/chroma:latest
volumes:
- chromadb-data:/chroma/chroma
ports:
- "127.0.0.1:8000:8000"
environment:
- IS_PERSISTENT=TRUE
- ANONYMIZED_TELEMETRY=FALSE
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/heartbeat"]
interval: 15s
timeout: 5s
retries: 3
# ── LLM API proxy ──
litellm:
image: ghcr.io/berriai/litellm:main-latest
command: ["--config", "/app/config.yaml", "--port", "4000"]
volumes:
- ./litellm/config.yaml:/app/config.yaml:ro
ports:
- "127.0.0.1:4000:4000"
environment:
- LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY}
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
- SILICONFLOW_API_KEY=${SILICONFLOW_API_KEY}
- DEEPINFRA_API_KEY=${DEEPINFRA_API_KEY}
- GROQ_API_KEY=${GROQ_API_KEY}
- CEREBRAS_API_KEY=${CEREBRAS_API_KEY}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health/liveliness"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
# ── Chat UI ──
open-webui:
image: ghcr.io/open-webui/open-webui:main
volumes:
- open-webui-data:/app/backend/data
ports:
- "127.0.0.1:3000:8080"
environment:
- OLLAMA_BASE_URL=
- OPENAI_API_BASE_URL=http://litellm:4000/v1
- OPENAI_API_KEY=${LITELLM_MASTER_KEY}
- ENABLE_RAG_WEB_SEARCH=true
- RAG_WEB_SEARCH_ENGINE=searxng
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json
- CHROMA_HTTP_HOST=chromadb
- CHROMA_HTTP_PORT=8000
- WEBUI_AUTH=true
depends_on:
litellm:
condition: service_healthy
chromadb:
condition: service_healthy
restart: unless-stopped
# ── Cloudflare Tunnel (public HTTPS) ──
cloudflared:
image: cloudflare/cloudflared:latest
command: tunnel run
environment:
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
restart: unless-stopped
# ── Tailscale (private VPN access) ──
tailscale:
image: tailscale/tailscale:latest
hostname: hetzner-stack
volumes:
- tailscale-state:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false
restart: unless-stopped
network_mode: host
volumes:
valkey-data:
chromadb-data:
open-webui-data:
tailscale-state:

64
litellm/config.yaml Normal file
View file

@ -0,0 +1,64 @@
model_list:
# --- OpenRouter models ---
- model_name: kimi-k2.5
litellm_params:
model: openrouter/moonshotai/kimi-k2.5
api_key: os.environ/OPENROUTER_API_KEY
- model_name: devstral
litellm_params:
model: openrouter/mistralai/devstral-small
api_key: os.environ/OPENROUTER_API_KEY
- model_name: minimax-m2
litellm_params:
model: openrouter/minimax/minimax-m1
api_key: os.environ/OPENROUTER_API_KEY
- model_name: gpt-oss
litellm_params:
model: openrouter/openai/gpt-4.1-mini
api_key: os.environ/OPENROUTER_API_KEY
# --- SiliconFlow models ---
- model_name: glm-4.7
litellm_params:
model: openai/THUDM/GLM-4-32B-0414
api_base: https://api.siliconflow.cn/v1
api_key: os.environ/SILICONFLOW_API_KEY
- model_name: qwen3-coder
litellm_params:
model: openai/Qwen/Qwen3-Coder
api_base: https://api.siliconflow.cn/v1
api_key: os.environ/SILICONFLOW_API_KEY
# --- DeepInfra models ---
- model_name: deepseek-v3.2
litellm_params:
model: deepinfra/deepseek-ai/DeepSeek-V3-0324
api_key: os.environ/DEEPINFRA_API_KEY
- model_name: devstral-deepinfra
litellm_params:
model: deepinfra/mistralai/Devstral-Small-2505
api_key: os.environ/DEEPINFRA_API_KEY
# --- Groq (free/fast) ---
- model_name: llama-3.3-70b
litellm_params:
model: groq/llama-3.3-70b-versatile
api_key: os.environ/GROQ_API_KEY
# --- Cerebras (free/fast) ---
- model_name: llama-3.3-70b-cerebras
litellm_params:
model: cerebras/llama-3.3-70b
api_key: os.environ/CEREBRAS_API_KEY
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
litellm_settings:
drop_params: true
set_verbose: false

52
searxng/settings.yml Normal file
View file

@ -0,0 +1,52 @@
use_default_settings: true
general:
instance_name: "SearXNG"
privacypolicy_url: false
donation_url: false
enable_metrics: false
search:
safe_search: 0
autocomplete: "google"
formats:
- html
- json
server:
secret_key: "${SEARXNG_SECRET_KEY}"
limiter: false
image_proxy: true
public_instance: false
ui:
static_use_hash: true
engines:
- name: google
engine: google
shortcut: g
- name: duckduckgo
engine: duckduckgo
shortcut: ddg
- name: brave
engine: brave
shortcut: br
- name: wikipedia
engine: wikipedia
shortcut: wp
- name: github
engine: github
shortcut: gh
- name: stackoverflow
engine: stackoverflow
shortcut: so
- name: arxiv
engine: arxiv
shortcut: arx