Nginx. How to configure locations for a virtual host
Locations define how Nginx handles requests to different URL paths of a virtual host. Through them you can wire in PHP, set up reverse proxying to another service, restrict access by IP, override the root folder for a sub-path, and tune other parameters. This article is for those who already created a virtual host by following Nginx. Working with virtual hosts and now want to work through the «Extra options» section in the builder form. If the form does not cover your scenario (for example, rewrite, if, or map directives), use expert mode.
Where locations live
On the virtual host create or edit page, below the main fields, expand the «Extra options» block and click «Add location» — the panel offers a template to choose from and creates a card. The order of cards in the form matches the order of location blocks inside server.
Location templates
When you add a location, you pick one of four templates. The template determines which template-specific fields appear on the card and which nginx directives end up in the resulting location block. The root location is always present and created automatically — its template cannot be changed; the other three are picked manually.
Root location
The root location is the location / block in the nginx config. All requests that did not match a more specific location go through it. Its card is always first in the form; the path is fixed at /, the template selector is hidden, and there is no delete button. Only the «Enabled / Disabled» toggle and the universal parameters are available.
By default the root location already has two parameters set:
- «Serve files (try_files)» =
$uri $uri/ =404— the standard scheme for serving static files: Nginx first looks for the requested file, then a directory, otherwise responds with 404. - «Max request body size» =
10m— the request body size limit.
Either default can be changed or removed; the rest of the universal parameters are added the usual way. The root location itself can also be turned off with the toggle (see Enabling and disabling a location) — for example, to describe root handling entirely through separate locations or universal parameters.
Simple
The «Simple» template is an empty location block with an arbitrary "path" and a set of universal parameters. It has no template-specific fields — behaviour is configured by adding parameters. Typical scenarios:
- restrict access by IP for the
/admin/directory; - override the root folder for
/static/; - set a long
expiresfor assets; - block access to service files like
.git.
Worked example: a rule for a static directory
Suppose the Simple location form has the path /static/, with «Cache lifetime (expires)» = 30d, «Max request body size» = 10m, and «Allow access (allow)» = all added through «Add parameter». The resulting *.conf file will contain roughly this block:
location /static/ {
expires 30d;
client_max_body_size 10m;
allow all;
}The Simple template adds no directives of its own — only what you set in the parameters ends up in the block.
PHP (FastCGI)
The PHP (FastCGI) template configures forwarding requests to PHP-FPM — the typical setup for WordPress, Laravel, and other PHP applications. When the template is selected, the Matcher field is automatically filled with the regular expression ~ \.php$ — it matches any request ending in .php. In most cases this value does not need to change.
If at least one location in the host uses the PHP (FastCGI) template, BeAdmin automatically prepends index.php to the host's index file list. When such a location is removed, index.php is automatically taken out of the list.
PHP version
The PHP version is the only template-specific field. Based on the chosen version, BeAdmin substitutes the path to the matching FPM socket: unix:/var/run/php/php<X.Y>-fpm.sock. If the chosen version is not yet installed on the system, you can install it right from this control — there is no need to go to the PHP section separately.
💡 What the panel adds on top of your parameters
Besides fastcgi_pass for the chosen PHP version, BeAdmin adds a standard set of FastCGI directives to the block: fastcgi_split_path_info, try_files $fastcgi_script_name =404, include fastcgi_params, and the basic fastcgi_param lines. Since try_files is fixed, the user-supplied Serve files (try_files) parameter is ignored in the PHP template — there is no point in setting it.
Worked example: a PHP location in the resulting config
Suppose the PHP location form has the path ~ \.php$, PHP 8.3 selected, and Max request body size = 64m plus Cache lifetime (expires) = 1h added through Add parameter. The resulting *.conf file will contain roughly this block:
location ~ \.php$ {
# Parameters from the form
client_max_body_size 64m;
expires 1h;
# PHP-FPM socket for the chosen version
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
# Standard FastCGI scaffolding from BeAdmin
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
try_files $fastcgi_script_name =404;
set $path_info $fastcgi_path_info;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param PATH_TRANSLATED $document_root$path_info;
fastcgi_param HTTP_PROXY "";
}The first two directives are the parameters you added in the form. Everything else BeAdmin fills in itself based on the chosen PHP version and the standard FastCGI handling template.
Reverse proxy
The «Reverse proxy» template turns the location block into a reverse proxy: requests on the chosen path go to an internal backend (another Nginx, Apache on 127.0.0.1:8808, a Node app, a Docker container). When the template is selected, the «Matcher» field is cleared — set it yourself: most often it is /, /api, or ^~ /api/.
Proxy pass target (proxy_pass)
The «Proxy pass target (proxy_pass)» field takes the backend URL — for example, http://127.0.0.1:8080 or https://api.internal.example.com/v2. This value goes into the proxy_pass directive. The field is required; without it the location will not save.
Headers
The «Headers» sub-section lets you forward additional HTTP headers to the backend through proxy_set_header. The «Add header» button adds a name-value pair. The name is picked from a fixed list: Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port, Connection, Upgrade, Accept-Encoding, Accept-Language, Authorization, Content-Type, Content-Length, User-Agent, Referer, Origin, Cache-Control, Cookie, Set-Cookie. If the header you need is not on the list, the only path is expert mode.
A typical set for an Nginx + Apache pairing: Host = $host, X-Real-IP = $remote_addr, X-Forwarded-For = $proxy_add_x_forwarded_for, X-Forwarded-Proto = $scheme.
Worked example: proxying to a local Node app
Suppose the Reverse proxy form has the path /, «Proxy pass target (proxy_pass)» = http://127.0.0.1:8080, and through «Add header» the pairs Host = $host and X-Real-IP = $remote_addr are added. The resulting *.conf file will contain roughly this block:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}The Reverse proxy template adds only proxy_pass and proxy_set_header for the listed headers; everything else is set through universal parameters or expert mode.
Universal parameters
Every template has a Parameters sub-section and an Add parameter button. Underneath is a list of seven keys shared across all templates. Each key can be added to a card only once; ones already in use are hidden. The table shows what each parameter means in the nginx config and how the form validates it.
| Form parameter | In *.conf | What it sets and how it is validated |
|---|---|---|
| Allow access (allow) | allow <value>; | The list of addresses allowed to access the location. Each value is an IPv4 address (192.168.1.100), a CIDR network (192.168.1.0/24, mask from 0 to 32), or the keyword all. Multiple values are entered one after another through a dropdown. |
| Deny access (deny) | deny <value>; | Same as above, but denies access. The usual pairing is several allow entries for your own networks and deny all at the end. |
| Max request body size | client_max_body_size <value>; | Request body size limit. The format is a number with an optional k, m, or g suffix: 100m, 10k, 1g, 0. |
| Cache lifetime (expires) | expires <value>; | The Expires header for browser-side caching. The dropdown lists the presets off, 1m, 30m, 1h, 24h, 7d, 30d, 1y; you can also type your own value, for example -1h or max. |
| Log 404 errors | log_not_found on/off; | Toggle: whether to write Nginx log entries about not-found files. |
| Root folder (root_dir) | root <value>; | The root folder for this location — overrides the host-level root for a specific path. The field must not be empty. |
| Serve files (try_files) | try_files <value>; | The full argument string of the try_files directive, for example $uri $uri/ =404 or $uri /index.php?$query_string. In the PHP (FastCGI) template this parameter is ignored — try_files is fixed there. |
⚠️ IPv6 in Allow access and Deny access
The form accepts only IPv4 addresses and IPv4 CIDR networks. For IPv6 restrictions you need expert mode — there allow and deny go straight into the config and support any Nginx syntax.
Enabling and disabling a location
Every location card, including the root one, has an Enabled / Disabled toggle. A disabled location stays in the form but does not end up in the resulting *.conf for Nginx — a convenient way to temporarily switch off a piece of configuration without losing its settings. As a side effect, a disabled location is exempt from the duplicate-matcher check: you can disable an old location with the matcher /api and create a new one with the same matcher — saving will succeed.