When setting up a Symfony application with Nginx and PHP-FPM in Docker, a common stumbling block is the "Primary script unknown" error. This typically occurs when Nginx fails to properly communicate with PHP-FPM about the script location, particularly in complex routing scenarios where you need to:
- Serve static files from one directory (/public)
- Route API requests to a Symfony front controller (/api/index.php)
The original configuration has several issues that trigger this error:
# Problematic original config
location /api {
root /usr/share/nginx/html/api; # This changes root context
try_files $uri /index.php; # Doesn't properly handle PHP requests
}
Here's the working solution that properly handles both static files and Symfony routing:
upstream php {
server php:9000;
}
server {
listen 80 default_server;
server_name impressive.local;
root /usr/share/nginx/html/public;
# API路由处理
location /api {
alias /usr/share/nginx/html/api/public;
try_files $uri /index.php$is_args$args;
location ~ \.php$ {
fastcgi_pass php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
}
# 静态文件处理
location / {
try_files $uri $uri/ =404;
}
# 全局PHP处理 (备选方案)
location ~ \.php$ {
return 404; # Explicitly block direct PHP access outside /api
}
}
The critical adjustments that fixed the issue:
# Using alias instead of root for precise path mapping
alias /usr/share/nginx/html/api/public;
# Proper PHP-FPM parameters
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param DOCUMENT_ROOT $realpath_root;
# Correct try_files syntax for Symfony
try_files $uri /index.php$is_args$args;
The docker-compose.yml also needs proper volume mappings:
version: '3'
services:
web:
image: nginx:alpine
volumes:
- ./web/public:/usr/share/nginx/html/public
- ./web/api:/usr/share/nginx/html/api
- ./nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
depends_on:
- php
php:
image: php:7.4-fpm-alpine
volumes:
- ./web/api:/var/www/api
- ./web/public:/var/www/public
To test if everything works correctly:
- Access static files:
http://localhost:8080/index.html
- Access API endpoint:
http://localhost:8080/api/endpoint
- Check error logs:
docker-compose logs -f php
- Mixing root and alias directives incorrectly
- Incorrect filesystem permissions (PHP-FPM needs read access)
- Missing fastcgi_param configurations
- Path mismatches between Docker containers
When configuring Nginx to route API requests to PHP-FPM while serving static content separately, we often encounter the "Primary script unknown" error. This occurs when PHP-FPM can't locate the script that Nginx is trying to execute.
The current setup has several issues:
# Current problematic location block
location /api {
root /usr/share/nginx/html/api;
try_files $uri /index.php;
}
The main problems are:
- Incorrect root directive placement
- Missing proper PHP handler for API routes
- Improper try_files configuration
Here's the corrected Nginx configuration:
upstream php {
server php:9000;
}
server {
listen 80 default_server;
server_name impressive.local;
index index.html index.php;
root /usr/share/nginx/html/public;
location /api {
alias /usr/share/nginx/html/api;
try_files $uri /api/index.php$is_args$args;
}
location ~ \\.php$ {
fastcgi_pass php;
fastcgi_split_path_info ^(.+\\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
}
1. Using alias instead of root: The alias directive is more appropriate when mapping URI prefixes to filesystem paths.
2. Proper try_files directive: The new version explicitly routes missing files to index.php with preserved query parameters.
3. Enhanced PHP handler: Added crucial fastcgi parameters to ensure proper script location resolution.
For Docker environments, ensure your volumes are properly mounted. Verify the paths match between Docker and Nginx configurations:
volumes:
- ./web:/usr/share/nginx/html
Check the actual files exist in the container:
docker exec -it container_name ls -la /usr/share/nginx/html/api/
For Symfony applications, consider these additional optimizations:
location /api {
alias /usr/share/nginx/html/api;
try_files $uri /api/index.php$is_args$args;
# Symfony specific additions
fastcgi_param APP_ENV prod;
fastcgi_param APP_DEBUG 0;
}
After making changes:
nginx -t
service nginx reload
Test the API endpoint:
curl -I http://localhost:8080/api/test
- Permission issues: Ensure PHP-FPM worker has read access to the files
- Path mismatches: Verify all paths are absolute and correct
- Caching problems: Clear opcache if you're making frequent changes