- 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
- Debian/Ubuntu (apt):
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.