Skip to content

Automating Shoko Server Setup with Ansible (No GUI Required)

How to fully automate Shoko Server deployment — including admin user creation, AniDB credential configuration, and import folder setup — without ever opening the web UI.

The Problem

Shoko Server's first-run experience requires you to:

  1. Open the web UI and create an admin account
  2. Enter your AniDB credentials
  3. Complete the setup wizard
  4. Configure import folders for your anime collection

For IaC deployments, all of this should happen automatically. Shoko exposes a v3 REST API that makes full automation possible, though the API has some quirks that aren't immediately obvious from the documentation.

Prerequisites

  • Docker and Docker Compose
  • An AniDB account (free, required for anime metadata)
  • (Optional) Ansible for full automation

Step 1: Deploy the Container

Shoko uses SQLite internally — no external database needed:

services:
  shoko-server:
    image: shokoanime/server:latest
    container_name: shoko-server
    environment:
      - PUID=1000
      - PGID=100
      - TZ=America/New_York
    ports:
      - "8111:8111"
    volumes:
      - ./shoko-config:/home/shoko/.shoko   # Persistent config (SQLite DB)
      - ./anime:/anime                       # Anime library
      - ./drop:/drop                         # Drop folder for new files
    restart: unless-stopped

Step 2: Wait for Startup and Check Status

Shoko has a startup state machine. After launching, check its status:

curl -s http://localhost:8111/api/v3/Init/Status | jq

States: - "Waiting" — first run, ready for setup - "Starting" — server is initializing - "Started" — fully running, setup already completed

Step 3: Create Admin User

When in Waiting state, create the default admin user:

curl -sf -X POST "http://localhost:8111/api/v3/Init/DefaultUser" \
  -H "Content-Type: application/json" \
  -d '{
    "Username": "admin",
    "Password": "your-secure-password"
  }'

Note the PascalCase field names — Shoko's API uses .NET conventions.

Step 4: Configure AniDB Credentials

Shoko uses RFC 6902 JSON Patch for settings updates (not regular JSON):

curl -sf -X PATCH "http://localhost:8111/api/v3/Settings" \
  -H "Content-Type: application/json-patch+json" \
  -d '[
    {"op": "replace", "path": "/AniDb/Username", "value": "your-anidb-username"},
    {"op": "replace", "path": "/AniDb/Password", "value": "your-anidb-password"}
  ]'

Key detail: The Content-Type must be application/json-patch+json, not application/json. The settings endpoint uses RFC 6902 patch operations.

Test AniDB Connection

Verify the credentials work before completing setup:

curl -sf -X POST "http://localhost:8111/api/v3/Settings/AniDB/TestLogin" \
  -H "Content-Type: application/json" \
  -d '{
    "Username": "your-anidb-username",
    "Password": "your-anidb-password"
  }'

Step 5: Complete Setup

The endpoint to finish setup is StartServer, not CompleteSetup:

curl -sf "http://localhost:8111/api/v3/Init/StartServer"

This is a GET request, not POST. After calling it, Shoko transitions from WaitingStartingStarted. Wait for it:

# Poll until started (with timeout)
for i in $(seq 1 60); do
  STATE=$(curl -s http://localhost:8111/api/v3/Init/Status | jq -r '.State')
  [ "$STATE" = "Started" ] && break
  sleep 5
done

Step 6: Authenticate

Once started, get an API key for subsequent requests:

API_KEY=$(curl -sf -X POST "http://localhost:8111/api/auth" \
  -H "Content-Type: application/json" \
  -d '{
    "user": "admin",
    "pass": "your-secure-password",
    "device": "automation"
  }' | jq -r '.apikey')

The API key is persistent — store it securely for future use.

Step 7: Add Import Folders

Check existing folders and add new ones:

# List existing folders
curl -s "http://localhost:8111/api/v3/ImportFolder" \
  -H "apikey: $API_KEY" | jq '.[].Path'

# Add anime library folder
curl -sf -X POST "http://localhost:8111/api/v3/ImportFolder" \
  -H "apikey: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Path": "/anime",
    "Name": "Anime",
    "DropFolderType": 1,
    "WatchForNewFiles": true
  }'

# Add drop folder (for new file imports)
curl -sf -X POST "http://localhost:8111/api/v3/ImportFolder" \
  -H "apikey: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Path": "/drop",
    "Name": "Drop",
    "DropFolderType": 0,
    "WatchForNewFiles": true
  }'

DropFolderType values: - 0 — Drop/source folder (Shoko moves files from here) - 1 — Destination folder (where organized files live)

API Quirks and Gotchas

  1. PascalCase everywhere — field names use .NET PascalCase: Username, Password, DropFolderType, not camelCase.

  2. Settings use RFC 6902 PATCH — don't send a regular JSON body to PATCH /api/v3/Settings. Use JSON Patch operations (op, path, value) with Content-Type: application/json-patch+json.

  3. StartServer, not CompleteSetup — the endpoint name in the API doesn't match what you'd expect from the UI terminology.

  4. ImportFolder, not ManagedFolder — the API endpoint uses ImportFolder, even though the UI may refer to "managed folders."

  5. GET /api/v3/Init/StartServer — this is a GET request, not POST. Unusual but that's how the API works.

  6. Auth header is apikey, not Authorization — Shoko uses a custom header, not Bearer tokens.

  7. Wait for Started state — after calling StartServer, the server needs time to initialize. Don't try to authenticate or add folders until State == "Started".

Force Clean

Shoko uses SQLite, so a fresh start only requires wiping the config directory:

# Stop the container
docker compose down

# Wipe config (includes SQLite DB)
rm -rf ./shoko-config

# Recreate and restart
mkdir -p ./shoko-config
docker compose up -d

Ansible Automation Summary

The full Ansible playbook follows this sequence:

  1. Fetch secrets from your secret store (AniDB creds, Shoko admin creds)
  2. (Optional) Wipe config directory if force_clean=true
  3. Deploy the container
  4. Wait for readinessGET /api/v3/Init/Status returns 200
  5. Check setup state — if State == "Waiting", run first-time setup: a. Create admin user — POST /api/v3/Init/DefaultUser b. Configure AniDB — PATCH /api/v3/Settings (JSON Patch) c. Test AniDB login — POST /api/v3/Settings/AniDB/TestLogin d. Complete setup — GET /api/v3/Init/StartServer e. Wait for Started state
  6. AuthenticatePOST /api/auth to get API key
  7. Store API key back in your secret store
  8. Add import foldersPOST /api/v3/ImportFolder (idempotent with existence check)

API Reference

Endpoint Method Auth Purpose
/api/v3/Init/Status GET None Check server state
/api/v3/Init/DefaultUser POST None (setup only) Create admin user
/api/v3/Settings PATCH None (setup) / apikey Update settings (JSON Patch)
/api/v3/Settings/AniDB/TestLogin POST None (setup) / apikey Test AniDB credentials
/api/v3/Init/StartServer GET None (setup only) Complete setup and start server
/api/auth POST None Get persistent API key
/api/v3/ImportFolder GET/POST apikey List/create import folders

References