Visual orchestrator for fine-tuning LLMs via the Tinker SDK (ThinkingMachines)
EaseTinker is a web application that simplifies the LLM fine-tuning process using the Tinker platform. No Python knowledge required — configure, launch, and monitor training jobs directly from your browser.
- Overview
- Architecture
- Features
- Prerequisites
- Deploy on Hostinger VPS
- Updating to a New Version
- Local Development
- Environment Variables
- Contributing
- License
The Tinker SDK is powerful for fine-tuning LLMs, but it requires Python knowledge, manual training loop management, and terminal-based monitoring.
EaseTinker provides an intuitive web interface to orchestrate everything visually. Simply provide your Tinker Console API key, and the application handles the rest — managing datasets, hyperparameters, and monitoring training loss in real time.
The system runs two main services packaged with Docker Compose:
- Next.js (App) — Frontend, Authentication, UI, and REST Gateway.
- Python Worker — Communicates exclusively via internal network with Next.js and connects externally to Tinker Cloud via gRPC.
┌──────────────────────────────────────────────────────┐
│ Hostinger VPS │
│ ┌──────────┐ ┌─────────────────────────────────┐ │
│ │ Traefik │───▶│ Docker Compose Network │ │
│ │(Hostinger│ │ ┌───────────┐ ┌────────────┐ │ │
│ │ managed) │ │ │ Next.js │ │ Python │ │ │
│ └──────────┘ │ │ App :3000 │──│ Worker:8000│ │ │
│ │ └─────┬─────┘ └─────┬──────┘ │ │
│ │ │ │ │ │
│ │ ┌─────┴─────┐ ┌─────┴──────┐ │ │
│ │ │PostgreSQL │ │ Redis │ │ │
│ │ └───────────┘ └────────────┘ │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
- OAuth Authentication — Sign in with Google or GitHub
- Project Management — Create and manage multiple fine-tuning projects
- Dataset Upload — Upload files or link external data sources
- Training Orchestration — Configure hyperparameters (LoRA rank, learning rate, epochs, batch size) and launch jobs
- Real-time Monitoring — Watch training loss metrics live via Redis pub/sub
- Credential Encryption — Tinker API keys encrypted at rest with AES-256-GCM
- Self-hosted — Runs entirely on your own VPS with Docker Compose
- Hostinger VPS with Ubuntu 22.04+ and Docker pre-installed
- A domain pointing to your VPS IP (e.g.
easetinker.yourdomain.com) - Traefik reverse proxy running (default on Hostinger Docker images)
- Google and/or GitHub OAuth app credentials
EaseTinker is designed to be hosted on a Hostinger VPS with Docker and Traefik. Traefik automatically detects the labels in docker-compose.yml and manages SSL/HTTPS certificate issuance.
Make sure your domain is already pointing to your VPS IP address. The Docker stack assumes a Traefik instance is already running on the host (any configuration — bridge, host mode, etc).
Clone the stable branch — that's the production-ready line. (main is active development.)
git clone -b stable https://github.com/danielbfs/easetinker.git /docker/easetinker
cd /docker/easetinkercp .env.example .env
nano .envFill in the following required values:
| Variable | Description | How to obtain |
|---|---|---|
APP_DOMAIN |
Your exact domain (no https://) |
e.g. easetinker.yourdomain.com |
GOOGLE_CLIENT_ID |
Google OAuth client ID | Google Cloud Console |
GOOGLE_CLIENT_SECRET |
Google OAuth secret | Google Cloud Console |
GITHUB_CLIENT_ID |
GitHub OAuth client ID | GitHub Developer Settings |
GITHUB_CLIENT_SECRET |
GitHub OAuth secret | GitHub Developer Settings |
OAuth Callback URLs — When creating OAuth apps, set the callback URL to:
https://easetinker.yourdomain.com/api/auth/callback/google(and/github)
Technical secrets are auto-generated.
POSTGRES_PASSWORD,NEXTAUTH_SECRET,ENCRYPTION_KEY, andWORKER_SECRETare generated on first deploy by theinit-secretscontainer and stored in thesecretsnamed volume — you don't need to put them in.env. See.env.examplefor details on rotation.
docker compose up -d --buildThis creates 5 containers:
init-secrets— runs once on first boot, generates technical secrets into thesecretsvolume, then exitseasetinker-postgres— PostgreSQL 16 database (reads its password from thesecretsvolume)easetinker-redis— Redis 7 cache and job queueeasetinker-worker— Python FastAPI worker (internal only)easetinker-app— Next.js app (exposed via Traefik with HTTPS)
docker compose exec app /usr/local/bin/docker-entrypoint.sh pnpm exec prisma migrate deployThe migration command goes through the entrypoint script so that it picks up
DATABASE_URLand the other secret-derived env vars (the entrypoint reads them from thesecretsvolume;docker execby default does NOT inherit env vars exported by the container's main process).
Use
pnpm exec(notnpx), so the Prisma version pinned inpackage.jsonis used.npx prismawill silently fetch the latest version from the registry, which can be incompatible.
# Check all containers are healthy
docker compose ps
# Inspect logs if something is wrong
docker compose logs -f app
docker compose logs -f workerOpen https://easetinker.yourdomain.com in your browser. Traefik configures SSL automatically.
Branch model. Production tracks the
stablebranch — it only advances when a release is cut. Day-to-day work happens onmainand may be unstable. Pre-releases (e.g.v0.2.0-beta.1) are tagged frommainfor semi-ready cuts. See Releases for the changelog.
Pick the section that matches how you set up the server in the first place.
If you installed via Hostinger's Docker Manager (the UI cloned the repo for you), the project directory /docker/easetinker/ only contains docker-compose.yml and .env — not a git checkout. To update:
- Open the Hostinger Docker Manager UI for the project.
- Click Rebuild (or Redeploy). Hostinger clones the latest
maininto a temporary directory, rebuilds the images, and restarts the containers. Your.envand named volumes are preserved. - After the rebuild finishes, apply migrations via SSH:
docker compose -p easetinker exec app /usr/local/bin/docker-entrypoint.sh pnpm exec prisma migrate deploy
This is the recommended update flow. It requires that /docker/easetinker/ is a git checkout — i.e., you either followed Step 2, or you previously converted a Hostinger-Docker-Manager layout into a clone (see below).
cd /docker/easetinker
# 1. Pull the latest stable release from GitHub
git pull origin stable
# 2. Rebuild images without cache (guarantees the new code lands)
docker compose build --no-cache
# 3. Restart services, dropping any orphan containers from previous compose layouts
docker compose up -d --remove-orphans
# 4. Apply any new database migrations
docker compose exec -T app /usr/local/bin/docker-entrypoint.sh pnpm exec prisma migrate deploy
# 5. (Optional) reclaim disk by pruning dangling images
docker image prune -f
# 6. Confirm everything is healthy
docker compose psNamed volumes (easetinker_postgres_data, easetinker_redis_data, easetinker_uploads, easetinker_secrets) and the project .env are not touched by these commands — user accounts, the database, and the auto-generated secrets all survive the update.
If you installed via the Hostinger Docker Manager UI, /docker/easetinker/ is not a git checkout. Run this once to convert it (preserves your .env and named volumes):
cd /docker
TS=$(date +%s)
mv easetinker easetinker.bak.$TS
git clone -b stable https://github.com/danielbfs/easetinker.git easetinker
cp easetinker.bak.$TS/.env easetinker/.env
chmod 600 easetinker/.env
# Verify the new directory looks right, then:
rm -rf /docker/easetinker.bak.$TSAfter this, do not click the Update/Rebuild button in the Hostinger UI again — it can overwrite the directory. Use the SSH flow above for every update.
Tip: Subscribe to GitHub Releases to get notified when new versions are published.
To work on EaseTinker locally before pushing to production:
1. Start support services (DB + Redis only):
docker compose -f docker-compose.dev.yml up -d2. Install Node dependencies:
pnpm install3. Set up the database:
pnpm prisma generate
pnpm prisma migrate dev4. Set up the Python Worker:
cd worker
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txt5. Copy and fill in environment variables:
cp .env.example .env
# Edit .env with your local values (use localhost URLs)6. Start both services in separate terminals:
# Terminal 1 — Next.js
pnpm dev
# Terminal 2 — Python Worker
cd worker && uvicorn main:app --reloadThe app will be available at http://localhost:3000.
See .env.example for the full list. You only fill in domain + OAuth in .env. The four technical secrets are generated automatically.
| Variable | Required | Description |
|---|---|---|
APP_DOMAIN |
Yes | Your domain (no https://) |
GOOGLE_CLIENT_ID |
Yes* | Google OAuth (*at least one provider required) |
GOOGLE_CLIENT_SECRET |
Yes* | Google OAuth |
GITHUB_CLIENT_ID |
Yes* | GitHub OAuth |
GITHUB_CLIENT_SECRET |
Yes* | GitHub OAuth |
POSTGRES_USER |
Yes | DB username (default easetinker) |
POSTGRES_DB |
Yes | DB name (default easetinker) |
MAX_FILE_SIZE_MB |
No | Max upload size (default: 50) |
UPLOAD_DIR |
No | Upload directory (default: /data/uploads) |
| Variable | Generated value | Used by |
|---|---|---|
POSTGRES_PASSWORD |
openssl rand -hex 32 |
Postgres (via POSTGRES_PASSWORD_FILE), app (via entrypoint) |
NEXTAUTH_SECRET |
openssl rand -base64 32 |
App (entrypoint) |
ENCRYPTION_KEY |
openssl rand -hex 32 |
App (entrypoint) |
WORKER_SECRET |
openssl rand -hex 32 |
App + Worker (entrypoint) |
DATABASE_URL, REDIS_URL, NEXTAUTH_URL, and WORKER_URL are composed automatically from the values above (DB URL by the entrypoint, the others in docker-compose.yml).
We welcome contributions! Please read CONTRIBUTING.md before submitting a pull request.
- Found a bug? Open an issue
- Have an idea? Request a feature
- Want to contribute code? Fork the repo, create a branch, and open a PR.
This project is licensed under the MIT License.