PHP Ollama API Example: Connect Your Laravel App to AI

Looking for a production-ready PHP Ollama API example? This guide walks you through integrating Ollama's AI models into a Laravel app with secure, real-world code.

Every week I'm asked how to hook up private large language models to PHP or Laravel projects, especially since Ollama took off. You're not alone if you want your own AI but don't want to mess with raw Python or pay for a cloud API.

Today I'll walk through a complete PHP Ollama API example with Laravel. By the end, you'll know: - How to connect your Laravel application to an Ollama server - How to securely send prompts and receive results - The right way to stream LLM responses in real time (like ChatGPT) - How to avoid subtle gotchas, especially with PHP's HTTP libraries - Security practices to keep your Ollama models and user data safe

I'll use up-to-date PHP (>=8.3), Laravel 11 LTS, and tested code that you can adapt for new models as Ollama evolves.

What Is the Ollama API and Why Use It?

Ollama lets you run large language models, like Meta's Llama 2 and Mistral, entirely on your own hardware with a simple HTTP API. Unlike hosted AI, there's: - No per-request pricing - No sending sensitive data to someone else's servers - Full control to pick, swap, or retrain open-source LLMs as needed

You download a model locally (Ollama supports dozens), then interact over a RESTful API. PHP developers often want to plug into this for chatbots, document search, summarizers, or custom workflow automation using Laravel. Compared to using a paid OpenAI API key, Ollama is cheaper, more private, and—if you're OK running the server—often faster for small-medium workloads.

  • Privacy: your data never leaves your server.
  • Lower costs: no per-request pricing.
  • Flexible: swap, retrain, or customize models easily.

How the Ollama API Works for PHP Developers

Ollama exposes multiple RESTful endpoints, including '/api/models' for listing, '/api/tags', '/api/generate' (for single prompt completion), and '/api/chat' (for full multi-turn chat/streaming). The endpoints respond with JSON and, when you enable streaming, will output a sequence of JSON lines—ideal for dynamic UIs.

Key details for PHP devs: - HTTP: Localhost (default 11434), customizable via config - Auth: None by default (see 'Securing' section later) - Models: Referenced by name, must be pulled/downloaded in advance (e.g. "llama2") - Standard (non-stream) replies: single JSON object - Streaming: Each token arrives as a single line of JSON (not SSE), which you parse and forward in real time

PHP has several good options for consuming this API: Laravel's HTTP client, Guzzle directly, or plain cURL. We'll use Laravel's HTTP client for its ease of use, but also demonstrate Guzzle for streaming.

  • POST to /api/chat for conversational AI (messages).
  • POST to /api/generate for text generation (single prompt).
  • GET /api/tags and /api/models to inspect model inventory.
  • Ollama's API responds with JSON, can stream lines for real-time UX.

Prerequisites: Setting Up Laravel and Ollama Locally

Before you start writing code for your PHP Ollama API example, you'll need to:

- Have PHP 8.3+ (7.4+ for basic Ollama, but Laravel 11 requires >=8.2) - Install Laravel 11 (or upgrade, see https://laravel.com/docs) - Ensure Composer is available for dependency management - Optionally have Node.js for a modern web UI (not required for backend) - Install Ollama. Visit https://ollama.com/download for binaries on macOS, Linux, and Windows. If you use Docker, see https://github.com/jmorganca/ollama/blob/main/docs/docker.md - Download a model: e.g., 'ollama pull llama2'. Larger models may require several GB of RAM.

Ollama defaults to http://localhost:11434 but can be bound to any host/port via environment variables. Ensure only apps inside your trust boundary can reach it (see Security).

Sample model start: $ ollama run llama2

In Docker: $ docker run -d --name ollama -p 11434:11434 -v ollama:/root/.ollama ollama/ollama

Pro Tip: Always check Ollama's official requirements and FAQ for your OS, as models/quantization methods and RAM/CPU/GPU needs evolve quickly.

  • PHP 8.3+ and Laravel 11 installed.
  • Ollama server running (try 'ollama pull llama2' and then 'ollama run llama2').
  • Network access from Laravel to Ollama (usually localhost for dev).
  • Docker users: expose port 11434 and ensure volume mounts are correct.
ollama run llama2

Step-by-Step PHP Ollama API Example: Call Ollama from Laravel

Let's wire up Laravel to send a chat completion to the Ollama API using Laravel's HTTP Client, with complete input validation and secure config.

**1. Create a dedicated controller** within Laravel:

php artisan make:controller OllamaController

**2. Add this method to app/Http/Controllers/OllamaController.php:**

```php use Illuminate\Http\Request; use Illuminate\Support\Facades\Http;

class OllamaController extends Controller { /** * Send a prompt to Ollama LLM and return a single response. */ public function chat(Request $request) { $prompt = $request->input('prompt', ''); if (!is_string($prompt) || trim($prompt) === '' || strlen($prompt) > 2000) { return response()->json(['error' => 'Invalid prompt.'], 422); } $ollamaHost = config('services.ollama.host', 'http://localhost:11434'); $model = config('services.ollama.model', 'llama2');

$body = [ 'model' => $model, 'messages' => [ [ 'role' => 'user', 'content' => $prompt ] ], 'stream' => false // no streaming yet ]; try { $response = Http::timeout(60) ->post("$ollamaHost/api/chat", $body); } catch (\Exception $e) { return response()->json(['error' => 'Connection error', 'details' => $e->getMessage()], 500); }

if ($response->failed()) { return response()->json(['error' => 'Ollama server error', 'details' => $response->body()], 500); } $data = $response->json(); return response()->json([ 'response' => $data['message']['content'] ?? '', 'raw' => $data ]); } } ```

**3. Route it in routes/api.php:** ```php use App\Http\Controllers\OllamaController; Route::post('/ollama/chat', [OllamaController::class, 'chat']); ```

**4. Configure Ollama settings for safety and portability (config/services.php):** ```php 'ollama' => [ 'host' => env('OLLAMA_HOST', 'http://localhost:11434'), 'model' => env('OLLAMA_MODEL', 'llama2'), ], ```

And in your .env: ``` OLLAMA_HOST=http://localhost:11434 OLLAMA_MODEL=llama2 ```

**5. Test the endpoint using Postman/curl:** ``` curl -X POST http://localhost/api/ollama/chat -d 'prompt=Give me a PHP hello world.' ```

You should receive a well-formed JSON response with the AI's reply. If not, check: - Is Ollama running and the correct model loaded? - Does the model support chat? ('llama2' and 'mistral' both do) - Prompt was not blank or too long

**Extra tip:** To experiment safely, add logging in this method to diagnose JSON errors or server failures.

  • Single file, minimal dependencies.
  • JSON input and output for easy integration.
  • Handles timeouts, input validation, and API errors safely.
  • Uses Laravel config for model/host so you can swap LLMs without changing code.
  • Extensible: add auth, logging, or rate limiting in the same controller.
public function chat(Request $request)
{
    $prompt = $request->input('prompt');
    if (! $prompt) {
        return response()->json(['error' => 'No prompt provided'], 422);
    }
    $ollamaHost = config('services.ollama.host', 'http://localhost:11434');
    $model = config('services.ollama.model', 'llama2');

    $body = [
        'model' => $model,
        'messages' => [
            [ 'role' => 'user', 'content' => $prompt ]
        ],
        'stream' => false
    ];

    $response = Http::timeout(300)
        ->post("$ollamaHost/api/chat", $body);

    if ($response->failed()) {
        return response()->json(['error' => 'Ollama server error', 'details' => $response->body()], 500);
    }

    $data = $response->json();
    return response()->json([
        'response' => $data['message']['content'] ?? '',
        'raw' => $data
    ]);
}

Ollama API Streaming in PHP: Real-Time Response Example

For production chatbots and assistants, you need real-time streaming. Ollama supports streaming output as newline-delimited JSON objects (not native SSE events). Each JSON line includes a chunk of generated text, making it ideal for live UIs.

Laravel's HTTP client does not natively support client-to-server streaming, but you can: - Use Guzzle with 'stream' => true - Use Laravel's Response::stream() to deliver output progressively

Here's exactly how to implement this using Guzzle inside a Laravel controller, so each response chunk is sent as soon as received. This API endpoint is suitable for front-ends using EventSource, Fetch with 'Readablestream', or just progressive HTML rendering.

  • Use 'stream' => true in Ollama API body.
  • Read and forward streaming JSON lines to your front-end.
  • Set correct streaming headers for HTTP/1.1 chunked transfer.
  • Always validate and limit prompt/input sizes to keep memory low.
  • Compatible with React/Vue front-ends via Fetch, EventSource, or just plain JS.
use GuzzleHttp\Client as GuzzleClient;
use Symfony\Component\HttpFoundation\StreamedResponse;

public function stream(Request $request)
{
    $prompt = $request->input('prompt', '');
    if (!is_string($prompt) || trim($prompt) === '' || strlen($prompt) > 2000) {
        return response()->json(['error' => 'Invalid prompt.'], 422);
    }
    $ollamaHost = config('services.ollama.host', 'http://localhost:11434');
    $model = config('services.ollama.model', 'llama2');
    $body = [
        'model' => $model,
        'messages' => [
            [ 'role' => 'user', 'content' => $prompt ]
        ],
        'stream' => true
    ];
    $guzzle = new GuzzleClient(['timeout' => 300]);

    return response()->stream(function () use ($guzzle, $ollamaHost, $body) {
        $response = $guzzle->post("$ollamaHost/api/chat", [
            'json' => $body,
            'stream' => true,
            'headers' => ["Accept" => "application/json"]
        ]);
        $bodyStream = $response->getBody();
        while (!$bodyStream->eof()) {
            $line = trim($bodyStream->read(4096));
            if ($line) {
                echo $line . "\n";
                // For EventSource: echo "data: $line\n\n";
                ob_flush(); flush();
            }
        }
    }, 200, [
        'Content-Type' => 'application/json; charset=utf-8',
        'Cache-Control' => 'no-cache',
        'Connection' => 'keep-alive',
        // 'Transfer-Encoding' => 'chunked', // Laravel handles this
    ]);
}
// Route in routes/api.php:
// Route::post('/ollama/stream', [OllamaController::class, 'stream']);

Securing Your PHP Ollama API Integration

Self-hosting AI is great for privacy, but Ollama's REST API has no built-in authentication. Out of the box, it binds to 0.0.0.0 and is open to your whole LAN unless you override it. That is a severe risk: anyone could send requests, waste compute, or even prompt-inject.

**Security Checklist:** - Always bind Ollama to localhost (127.0.0.1) except in isolated private networks - Use system firewalls or Docker network rules to block external traffic - Never expose port 11434 directly to the public - For Laravel routes, use auth middleware (e.g. Sanctum, API tokens, OAuth) if exposing to logged-in users - Add explicit prompt sanitization and maximum length checks (as above) - Consider using Laravel's rate limiter (see https://laravel.com/docs/rate-limiting) to prevent brute force - Monitor and log all prompt traffic in production (via events or a middleware)

In public-facing web apps, keep client/UIs separated from the Ollama back end by a secure Laravel API. If you absolutely need to expose to a network, consider a reverse proxy (nginx) with IP allow-lists and use a jump host or VPN.

  • Run the Ollama server on localhost or within a VPN only.
  • Use Laravel auth or API token middleware for all /ollama/* routes.
  • Limit prompt size and sanitize input to defend against prompt injection.
  • Apply per-IP or per-user rate limits with Laravel's built-in features.
  • Log all failed and successful requests for audit and error tracing.

Common PHP Ollama API Errors (and Solutions)

Integrating with Ollama from PHP is reliable, but watch for these recurring issues:

1. **Connection refused or timeouts:** - Make sure the Ollama server is running and the correct port is accessible (use `netstat` or `ss` to confirm bindings). - On Docker: confirm port mapping (`-p 11434:11434`), and that containers can reach each other (check networks). - Firewalls can block the port; test with curl from inside your app container or host.

2. **Model not found or 400 errors:** - Ollama only serves models that have been previously downloaded (`ollama pull modelname`). - Check spelling/case. Available models are listed at https://ollama.com/library.

3. **Empty or malformed responses:** - This usually means the 'messages' structure is wrong, or the model can't handle your prompt size/type. - Always check log files for JSON decode errors.

4. **Prompt too large:** - Context limits are about 4k-32k tokens depending on the model (see model docs). - PHP memory limits or max_input_vars may also bite. Keep prompts under 2000 chars unless you know the model's safe context.

5. **CORS errors:** - If your web frontend calls Laravel, allow CORS in Laravel ('fruitcake/laravel-cors'). - Never expose Ollama's port itself to browsers, only allow frontend to talk to Laravel.

  • Verify Ollama server is running and accessible.
  • Ensure the requested model is pulled and loaded.
  • Send correct JSON (model, messages, properly shaped arrays).
  • Enforce prompt length and validate/sanitize unexpected input.
  • Web UIs: Ensure all CORS is handled at the Laravel layer.

Best Practices for Professional PHP Ollama API Integration

Production-grade PHP Ollama projects share these workflow traits:

- **Encapsulation:** Write a service class (e.g., `OllamaService`) to wrap all API calls. Inject via Laravel's service container for testability. - **Testing:** Use mock endpoints for unit/feature tests. Laravel's HTTP faking lets you verify your app logic without real Ollama servers. - **Error Logging:** Capture and store failed API responses and exceptions for later review. Use Laravel's logging system (Monolog). - **Timeouts and Retries:** All HTTP requests should be wrapped for timeouts and, optionally, exponential backoff/retry on failures (for flaky hardware/loads). - **Queueing for Long Jobs:** For complex prompts, consider Laravel queues so requests don't block main HTTP workers. Queue the Ollama call, then poll or subscribe for result. - **Config & Future-proofing:** Store model names, host URLs, API version in Laravel config so future Ollama versions/upgrades only require config change, not code changes. - **Sensitive Inputs:** For chatbots, pre-filter prompts for personally identifiable info before sending to LLMs.

  • Encapsulate API logic in a separate, injectable service class (OllamaService).
  • Mock/record HTTP traffic for tests (via Laravel's HTTP fakes).
  • Log all requests and responses for tracing/debug.
  • Use queues for async/long prompts, don't block HTTP worker.
  • Store model/endpoint config outside code for quick upgrade/rollbacks.
  • Prepare for future Ollama API changes by abstracting versioning/model selection.

Conclusion: Why PHP Ollama API Examples Matter

With Ollama and a modern PHP stack, you can build privacy-first AI features—such as chatbots, writers, or summarizers—entirely on your own terms. This differs from cloud solutions by keeping costs, data, and models in your hands. The real gap for most developers is not in the power of LLMs, but in robust, secure integration: validating user input, supporting streaming UIs, and preparing for real production scaling.

By following the code samples above—with input limits, server-side validation, secure config, and streaming—you can deliver the same feel as ChatGPT or Claude, but on open infrastructure. If you want further reading, visit https://ollama.com/docs for API details and official examples for upgrading models.

  • Ollama brings flexible, private LLMs to PHP and Laravel stacks.
  • Production-safe code is easy: Laravel HTTP client, streaming, and prompt validation.
  • Security matters: always shield Ollama from direct internet exposure.
  • Streaming approaches deliver great user experience for AI-powered chat.

Frequently asked questions

How do I call the Ollama API from PHP?

Use Laravel's HTTP client or Guzzle to send POST requests to /api/generate (for plain completions) or /api/chat (for chat apps). Always pass a well-formed JSON object: 'model', and (for chat) a 'messages' array. Use your model name from .env/config.

Can I use Ollama with Laravel for real-time AI chat?

Yes. By setting 'stream' => true, Ollama's /api/chat streams each response line as a JSON object you can forward to the client as received. Use Laravel's Response::stream() and the Guzzle HTTP client's 'stream' flag for best effect.

Is the Ollama API safe to expose to the internet?

No. Ollama's API has no authentication layered in by default. Always run it on localhost or within a private network/VPN, and expose only your secured Laravel API layer. Protect the Laravel endpoints further with authentication/middleware.

What should I do if I get a connection refused error from Ollama?

Double-check that the Ollama server is running and bound to your expected host and port (default: 11434). If running in Docker, ensure port forwarding is into the app container or localhost properly. Network tools like 'lsof' or 'ss' can confirm if the port is open.

How can I switch LLM models with Ollama in my PHP code?

Set your model name in Laravel's config/services.php and .env file (e.g. 'OLLAMA_MODEL=mistral'). Update your PHP code to use config('services.ollama.model') for each API call, so you can change models without touching your source files.