Skip to content
ESC

Searching...

Quick Links

Type to search • Press to navigate • Enter to select

Keep typing to search...

No results found

No documentation matches ""

Nginx Configuration.

Clean URL routing and security rules for VoxelSite on Nginx servers (Forge, RunCloud, Ploi, custom VPS).

Mar 8, 2026

Nginx Configuration

VoxelSite ships with an .htaccess file that handles clean URL routing and security rules on Apache. Nginx ignores .htaccess entirely — you need to add equivalent rules to your Nginx site configuration.

Without this configuration, visiting /about will show your homepage instead of about.php, because Nginx doesn't know to try the .php extension.

The essential fix: clean URLs

VoxelSite generates pages as PHP files (about.php, contact.php, etc.) and links to them with clean URLs (/about, /contact). On Apache, the .htaccess rewrite rule handles this automatically. On Nginx, you need to add a named location that rewrites extensionless URLs to .php:

Find the location / block in your Nginx config and replace it with:

# Clean URLs: /about → /about.php (processed by PHP)
location / {
    try_files $uri $uri/ @cleanurls;
}

location @cleanurls {
    rewrite ^/(.+)$ /$1.php last;
}

Why not $uri.php in try_files? Adding $uri.php as a middle argument in try_files finds the file but serves it as raw text — it bypasses the PHP handler. The named @cleanurls location with rewrite ... last does a proper internal redirect that re-evaluates against location ~ \.php$, ensuring PHP-FPM processes the file.

Recommended security blocks

The .htaccess also blocks access to sensitive directories and files. Add these before the location / block:

# Block sensitive directories
location ~ ^/(\.ai|\.git|scripts|vendor|node_modules|docs)/ {
    deny all;
    return 403;
}

# Block sensitive root files
location ~ ^/(composer\.(json|lock)|package(-lock)?\.json)$ {
    deny all;
    return 403;
}

# Block form definition files (contain spam protection config)
location ~ ^/assets/forms/.*\.json$ {
    deny all;
    return 403;
}

# Block sensitive file types
location ~ \.(db|sqlite|sqlite3|sql|sh|env|bak|log)$ {
    deny all;
    return 403;
}

Complete Nginx config example (Forge)

Here's a complete site configuration block for Laravel Forge. Replace the site ID (3050636) with your own:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/dhparams.pem;

add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";

index index.html index.htm index.php;

charset utf-8;

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/YOUR_SITE_ID/server/*;

# ── Security blocks ──

location ~ ^/(\.ai|\.git|scripts|vendor|node_modules|docs)/ {
    deny all;
    return 403;
}

location ~ ^/(composer\.(json|lock)|package(-lock)?\.json)$ {
    deny all;
    return 403;
}

location ~ ^/assets/forms/.*\.json$ {
    deny all;
    return 403;
}

location ~ \.(db|sqlite|sqlite3|sql|sh|env|bak|log)$ {
    deny all;
    return 403;
}

# ── Clean URL routing ──

location / {
    try_files $uri $uri/ @cleanurls;
}

location @cleanurls {
    rewrite ^/(.+)$ /$1.php last;
}

location = /favicon.ico { access_log off; log_not_found off; }
location = /favicon.svg { access_log off; log_not_found off; }
location = /robots.txt  { access_log off; log_not_found off; }

access_log off;
error_log  /var/log/nginx/YOUR_SITE_ID-error.log error;

error_page 404 /index.php;

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    include forge_fastcgi_defaults;
}

location ~ /\.(?!well-known).* {
    deny all;
}

Where to edit this on Forge

  1. Go to Sites → your site → Nginx Configuration (the "Edit" button on the files panel)
  2. Find the server { ... } block
  3. Replace the location / block and add the security rules
  4. Click Save — Forge automatically reloads Nginx

Ready to build?

One-time purchase. Self-hosted. Own every file forever.

Get VoxelSite