Kokoro-TTS Setup and Usage Guide: Building an Offline AI Text-to-Speech System on Linux

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

Background & Why You Should Self-Host Kokoro-TTS

Six months ago, our team’s automated call center and news briefing bots were burning through over $2,400 per month in ElevenLabs and Azure Speech API fees. Soaring bills were bad enough, but even more frustrating were the erratic network latencies ranging between 1.2s and 1.8s per request, along with client data privacy risks. Self-hosting an internal TTS cluster on Linux was our only way out.

We initially experimented with Bark, but it devoured RAM, pushing the RTF (Real-Time Factor) up to 4.0 on CPU. Switching to Coqui XTTS-v2 offered solid quality, but it demanded at least 4GB of VRAM, and synthesis speeds still lagged behind real-time conversational streams. Finally, Kokoro-TTS solved the entire puzzle. Packing just 82 million parameters (82M), it produces surprisingly natural voices and runs smoothly on standard CPUs without requiring expensive GPUs.

If you want full control over your audio pipeline and want to cut ties with costly cloud providers, Kokoro-TTS is currently the most cost-effective option available.

Setting Up the Environment and Kokoro-TTS on Linux

This guide uses Ubuntu 22.04 LTS as the baseline environment (the steps are identical on Debian 12). Because Kokoro relies on espeak-ng for phonemization, we need to install the core C/C++ packages first.

1. Installing OS Dependencies

sudo apt-get update && sudo apt-get install -y \
    python3-pip \
    python3-venv \
    espeak-ng \
    ffmpeg \
    libsndfile1

2. Initializing a Python Virtual Environment and Installing Libraries

Never install directly into your system Python. Always isolate your setup with venv:

mkdir -p /opt/kokoro-service && cd /opt/kokoro-service
python3 -m venv venv
source venv/bin/activate

# Install CPU-only PyTorch to minimize server costs
pip install --upgrade pip
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu

# Install Kokoro, soundfile, and numpy for audio array concatenation
pip install kokoro soundfile numpy

If your server is equipped with an NVIDIA GPU (such as a T4 or RTX 3060), simply switch the PyTorch installation command to the CUDA variant (e.g., cu121). Rendering speeds will jump 5x to 8x.

Building a REST API Service with FastAPI

With our libraries in place, we can write an audio generation script and package it as a REST API using FastAPI. This allows internal microservices to trigger synthesis via standard HTTP POST calls.

1. Basic Speech Generation Test in Python

Create a quick test file named test_speech.py:

import soundfile as sf
from kokoro import KPipeline

# Initialize pipeline for American English ('a') or British English ('b')
pipeline = KPipeline(lang_code='a')

text = "Kokoro is an efficient text to speech model running entirely on premise."

# Use the sample voice af_heart (female, warm, expressive tone)
generator = pipeline(text, voice='af_heart', speed=1.0, split_pattern=r'\n+')

for i, (gs, ps, audio) in enumerate(generator):
    sf.write(f'output_{i}.wav', audio, 24000)
    print(f"Exported output_{i}.wav | Samples: {len(audio)}")

Execute python test_speech.py. On the first run, the script automatically downloads the ~330MB checkpoint from Hugging Face into ~/.cache/huggingface/hub.

2. Wrapping into a Production-Ready FastAPI Service

Install the web server dependencies:

pip install fastapi uvicorn pydantic

Create app.py to handle stitching audio array segments into a single WAV file:

import io
import numpy as np
import soundfile as sf
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel
from kokoro import KPipeline

app = FastAPI(title="Kokoro TTS Private API")

# Load model once into memory on application startup
pipeline = KPipeline(lang_code='a')

class TTSRequest(BaseModel):
    text: str
    voice: str = "af_heart"
    speed: float = 1.0

@app.post("/v1/audio/speech")
def generate_speech(req: TTSRequest):
    clean_text = req.text.strip()
    if not clean_text:
        raise HTTPException(status_code=400, detail="Text cannot be empty")
    
    try:
        generator = pipeline(clean_text, voice=req.voice, speed=req.speed)
        segments = 
        
        if not segments:
            raise HTTPException(status_code=500, detail="Failed to synthesize audio")
        
        full_audio = np.concatenate(segments)
        
        buffer = io.BytesIO()
        sf.write(buffer, full_audio, 24000, format='WAV')
        buffer.seek(0)
        
        return Response(content=buffer.read(), media_type="audio/wav")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
def health_check():
    return {"status": "ok", "model": "Kokoro-82M"}

3. Managing the Daemon with Systemd

To ensure the service automatically recovers from crashes or server reboots, create a unit file at /etc/systemd/system/kokoro-tts.service:

[Unit]
Description=Kokoro TTS Offline API Service
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/opt/kokoro-service
ExecStart=/opt/kokoro-service/venv/bin/uvicorn app:app --host 0.0.0.0 --port 8080 --workers 1
Restart=always
RestartSec=5
Environment="PYTHONUNBUFFERED=1"

[Install]
WantedBy=multi-user.target

Take note of the --workers 1 parameter. When running on limited CPU cores or GPU memory, keeping a single worker prevents model duplication from exhausting your RAM/VRAM.

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable kokoro-tts
sudo systemctl start kokoro-tts

Testing & Real-World Performance Benchmarks

Now let’s run actual benchmarks to evaluate how the system performs under load.

1. Measuring Response Latency with cURL

Run a test request to measure the total round-trip delivery time:

time curl -X POST "http://localhost:8080/v1/audio/speech" \
     -H "Content-Type: application/json" \
     -d '{"text": "Your order number 1024 has been processed successfully.", "voice": "af_heart", "speed": 1.0}' \
     --output order_success.wav

Results on a €12/month 4 vCPU Hetzner VPS (x86_64): a 10-word sentence took just 260ms to generate a 3.2-second audio file. The RTF hovered around ~0.08, meaning synthesis was roughly 12 times faster than real-time speech.

2. Hardware Resource Usage

Monitor the running processes:

# Stream logs in real time
journalctl -u kokoro-tts -f

# Check RAM and CPU utilization
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | grep uvicorn

Over 6 months of continuous operation, the Uvicorn process consistently held steady between 480MB and 550MB of RAM in CPU mode, with zero signs of memory leaks. For production environments, consider placing an Nginx reverse proxy up front with rate limiting (e.g., max 15 requests/min per IP) and capping text payload lengths under 500 characters per request to prevent CPU queue bottlenecks.

Share: