Posted on
Artificial Intelligence

Artificial Intelligence PHP Hosting

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence PHP Hosting on Linux: A Practical, Bash‑Friendly Guide

AI isn’t just for Python shops anymore. If you run PHP in production, you can add AI-powered features today without rebuilding your stack. The challenge is hosting: how do you wire AI inference into a reliable, fast, and secure PHP deployment on Linux?

This guide shows a battle-tested approach using standard Linux tools and Bash. You’ll:

  • Stand up a lean PHP hosting stack on Debian/Ubuntu, Fedora/RHEL, or openSUSE

  • Integrate AI either via a hosted API or a local model server

  • Configure Nginx/PHP‑FPM for long-running AI calls

  • Offload slow AI requests to a Redis-backed worker

  • Ship with sensible production defaults

Works with your existing frameworks (Laravel, Symfony, Slim) or plain PHP.


Why this matters

  • PHP still serves a huge slice of the web. AI endpoints talk HTTP/JSON—perfect for PHP to call.

  • Linux offers predictable, automatable hosting with systemd, Nginx, and package managers.

  • You don’t have to run GPU stacks on the PHP box. Most teams do HTTP calls to hosted models or a separate inference server. Clean, secure, scalable.


1) Prepare the machine (Nginx, PHP‑FPM, Composer)

Install your web stack and dev tools. Choose the commands for your distro.

Debian/Ubuntu (apt):

sudo apt update
sudo apt install -y nginx php-fpm php-cli php-curl php-mbstring php-xml php-zip composer git unzip

Fedora/RHEL family (dnf):

sudo dnf install -y nginx php-fpm php-cli php-curl php-mbstring php-xml php-zip composer git unzip

openSUSE (zypper):

sudo zypper refresh
sudo zypper install -y nginx php8 php8-fpm php8-curl php8-mbstring php8-xml php8-zip composer git unzip

Enable and start services:

  • Nginx (all distros):
sudo systemctl enable --now nginx
  • PHP‑FPM:
    • Debian/Ubuntu (apt): sudo systemctl enable --now php$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')-fpm
    • Fedora/RHEL/openSUSE (dnf/zypper): sudo systemctl enable --now php-fpm

Optional (open HTTP firewall on Fedora/RHEL):

sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --reload

Create a simple app directory:

sudo mkdir -p /var/www/app/public
sudo chown -R $USER: /var/www/app

Minimal index.php to verify PHP:

cat > /var/www/app/public/index.php <<'PHP'
<?php phpinfo();
PHP

2) Choose your AI integration pattern

You have two reliable options. Start with A; move to B when you need full control or offline inference.

A) Call a hosted AI API over HTTPS (simplest)

Keep secrets out of code using environment variables:

export AI_ENDPOINT="https://your-ai-endpoint.example/v1/chat"
export AI_API_KEY="replace-with-your-api-key"

PHP example using cURL:

<?php
$endpoint = getenv('AI_ENDPOINT') ?: 'https://example.com/v1/chat';
$apiKey   = getenv('AI_API_KEY'); // may be null for self-hosted endpoints

$payload = [
  'model'  => 'general-llm',
  'messages' => [
    ['role' => 'system', 'content' => 'You are a concise assistant.'],
    ['role' => 'user',   'content' => 'Say hello in five words.']
  ],
  'stream' => false
];

$ch = curl_init($endpoint);
curl_setopt_array($ch, [
  CURLOPT_POST           => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => array_filter([
    'Content-Type: application/json',
    $apiKey ? 'Authorization: Bearer ' . $apiKey : null,
  ]),
  CURLOPT_POSTFIELDS     => json_encode($payload, JSON_UNESCAPED_UNICODE),
  CURLOPT_TIMEOUT        => 120,
]);
$response = curl_exec($ch);
if ($response === false) {
  http_response_code(502);
  echo "AI request failed: " . curl_error($ch);
  exit;
}
curl_close($ch);
header('Content-Type: application/json');
echo $response;

Notes:

  • Works with most hosted AI vendors (chat/completions style endpoints).

  • Keep timeouts ≥60–120s for longer model latencies.

  • Use HTTPS and Bearer tokens for security.

B) Run a local model server and call it from PHP

A popular choice for local LLMs is a small HTTP daemon that serves models on the same machine.

Install a local model server:

curl -fsSL https://ollama.com/install.sh | sh
# If a systemd unit is provided:
sudo systemctl enable --now ollama || true
# Otherwise, run in a user shell:
# ollama serve &

Download a model:

ollama pull llama3

Test from Bash:

curl -s http://localhost:11434/api/generate -d '{"model":"llama3","prompt":"Say hello","stream":false}'

Call it from PHP:

<?php
$endpoint = 'http://localhost:11434/api/generate';
$payload  = ['model' => 'llama3', 'prompt' => 'Write a haiku about Linux.', 'stream' => false];

$ch = curl_init($endpoint);
curl_setopt_array($ch, [
  CURLOPT_POST           => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
  CURLOPT_POSTFIELDS     => json_encode($payload, JSON_UNESCAPED_UNICODE),
  CURLOPT_TIMEOUT        => 180,
]);
$res = curl_exec($ch);
if ($res === false) { die("Local model error: " . curl_error($ch)); }
curl_close($ch);
echo $res;

Tip: Put the model server on its own host for heavier workloads; keep the PHP box stateless.


3) Configure Nginx + PHP‑FPM for AI workloads

AI requests can be slow; increase read timeouts and avoid buffering issues.

Create a site config (works on most distros):

sudo tee /etc/nginx/conf.d/ai-php.conf > /dev/null <<'NGINX'
server {
  listen 80;
  server_name _;
  root /var/www/app/public;
  index index.php;

  # Static files
  location ~* \.(png|jpg|js|css|svg|ico)$ {
    expires 7d;
    access_log off;
  }

  location / {
    try_files $uri /index.php?$args;
  }

  location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    # Choose ONE that matches your distro:
    # Fedora/openSUSE:
    fastcgi_pass unix:/run/php-fpm/www.sock;
    # Debian/Ubuntu (example for PHP 8.2):
    # fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    # TCP alternative (if you configured php-fpm to listen on 9000):
    # fastcgi_pass 127.0.0.1:9000;

    fastcgi_read_timeout 120s;      # allow longer AI calls
    fastcgi_connect_timeout 15s;
    fastcgi_send_timeout 120s;
  }

  client_max_body_size 10m;
}
NGINX
sudo nginx -t && sudo systemctl reload nginx

Adjust PHP settings for heavier requests:

sudo cp /etc/php/*/fpm/php.ini /tmp/php.ini.backup 2>/dev/null || true
sudo sed -i 's/^memory_limit = .*/memory_limit = 512M/' /etc/php/*/fpm/php.ini 2>/dev/null || true
sudo sed -i 's/^max_execution_time = .*/max_execution_time = 180/' /etc/php/*/fpm/php.ini 2>/dev/null || true
# Reload FPM (use the service name for your distro)
sudo systemctl reload php-fpm || sudo systemctl reload php$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')-fpm

4) Offload slow AI work to a Redis-backed PHP worker

For requests that may take 10–60+ seconds, don’t block the web request. Queue them and process asynchronously.

Install Redis:

  • Debian/Ubuntu (apt):
sudo apt install -y redis-server
sudo systemctl enable --now redis-server
  • Fedora/RHEL (dnf):
sudo dnf install -y redis
sudo systemctl enable --now redis
  • openSUSE (zypper):
sudo zypper install -y redis
sudo systemctl enable --now redis

Add a pure-PHP Redis client:

cd /var/www/app
composer require predis/predis:^2.0

Create a minimal worker that BLPOP’s jobs:

cat > /var/www/app/worker.php <<'PHP'
<?php
require __DIR__ . '/vendor/autoload.php';

$redis = new Predis\Client(getenv('REDIS_URL') ?: 'tcp://127.0.0.1:6379');
$aiEndpoint = getenv('AI_ENDPOINT') ?: 'http://localhost:11434/api/generate';
$apiKey = getenv('AI_API_KEY') ?: null;

fwrite(STDOUT, "AI worker started\n");
while (true) {
  $job = $redis->blpop(['ai:jobs'], 5); // waits up to 5s
  if (!$job) continue;

  [, $json] = $job;
  $data = json_decode($json, true);
  $id = $data['id'] ?? bin2hex(random_bytes(8));
  $prompt = $data['prompt'] ?? 'Hello from PHP';

  $payload = [
    'model' => $data['model'] ?? 'llama3',
    'prompt' => $prompt,
    'stream' => false
  ];

  $ch = curl_init($aiEndpoint);
  $headers = ['Content-Type: application/json'];
  if ($apiKey) $headers[] = 'Authorization: Bearer ' . $apiKey;

  curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
    CURLOPT_TIMEOUT => 180,
  ]);
  $res = curl_exec($ch);
  $err = $res === false ? curl_error($ch) : null;
  curl_close($ch);

  if ($err) {
    $redis->setex("ai:result:$id:error", 600, $err);
  } else {
    $redis->setex("ai:result:$id", 600, $res);
  }
}
PHP

Systemd unit for the worker (adjust User/Group to match your PHP-FPM user):

sudo tee /etc/systemd/system/ai-worker.service > /dev/null <<'UNIT'
[Unit]
Description=PHP AI Queue Worker
After=network.target redis.service

[Service]
Type=simple
User=www-data
Group=www-data
Environment=AI_ENDPOINT=http://localhost:11434/api/generate
Environment=REDIS_URL=tcp://127.0.0.1:6379
WorkingDirectory=/var/www/app
ExecStart=/usr/bin/php /var/www/app/worker.php
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target
UNIT

sudo systemctl daemon-reload
sudo systemctl enable --now ai-worker

Enqueue a job and read the result:

redis-cli LPUSH ai:jobs '{"id":"job-123","prompt":"Write a one-line limerick about Bash."}'
sleep 2
redis-cli GET ai:result:job-123
redis-cli GET ai:result:job-123:error

Expose an HTTP endpoint in your app that accepts a prompt, enqueues a job, and returns the job ID; provide a separate endpoint to poll the result key. This keeps web requests fast and resilient.


5) Production tips that save you hours

  • Timeouts and buffering

    • Set fastcgi_read_timeout ≥ 120s and PHP max_execution_time ≥ 180s for AI calls.
    • For streamed responses, consider server-sent events or chunked responses and ensure proxy buffering is disabled where needed.
  • Concurrency and memory

    • Right-size php-fpm pm.max_children (e.g., 10–50) based on RAM and request mix.
    • Use a queue for anything that might burst or exceed a few seconds.
  • Secrets

    • Put API keys in systemd Environment= or in /etc/default/* and not in code or repo.
  • Observability

    • Log request latency and error rates for AI calls in PHP and Nginx.
    • Use redis TTLs for results to avoid memory bloat.
  • Separation of concerns

    • Keep model serving on its own node/VM when it gets busy; PHP box stays stateless and easy to scale.

Real‑world example: “Ask Support” widget

  • A customer opens a chat widget on your PHP site.

  • Your app enqueues the user question to ai:jobs with a unique ID.

  • The worker sends the prompt to your chosen AI endpoint, stores the completion JSON in ai:result:{id}.

  • The frontend polls a small GET /chat/{id} endpoint that returns the stored result JSON when ready.

  • No long-running web requests, and you can scale workers without touching the web tier.


Conclusion and next steps

You don’t need to abandon PHP to ship AI features. With a standard Linux stack, a clean Nginx/PHP‑FPM setup, and either a hosted model API or a small local model server, you can deliver AI-powered endpoints today.

Your next step:

  • Choose A (hosted API) or B (local server), wire the PHP cURL snippet into your app, and deploy the Nginx config.

  • If you expect slow calls or bursts, add the Redis worker from step 4.

Questions or want a follow-up? Try building a tiny “/summarize” endpoint in your app using the patterns above. Once it’s live, you can iterate safely on prompts, models, and scale.