Manual nginx modifications
Using pre_virtual_host.conf and post_virtual_host.conf to add custom nginx configurations that survive rebuilds.
WSA automatically regenerates the nginx configuration (/etc/nginx/nginx.conf + all files in /etc/nginx/conf.d/) on every change. If you edit these files directly, your modifications will be overwritten on the next rebuild.
WSA provides two special files designed to persist administrator modifications:
/etc/nginx/pre_virtual_host.conf/etc/nginx/post_virtual_host.conf
This page explains when and how to use them.
1. Where these files fit in the nginx config
WSA builds the final nginx configuration by injecting these two files at specific moments in the main nginx.conf file:
http {
... # global http config (WSA)
proxy_cache_path /var/cache/nginx/... # cache zones (WSA)
map $http_user_agent ... # bot protection (WSA)
...
include /etc/nginx/pre_virtual_host.conf; ← YOUR directives, BEFORE vhosts
include /etc/nginx/conf.d/*.conf; # per-account vhosts (WSA)
include /etc/nginx/post_virtual_host.conf; ← YOUR directives, AFTER vhosts
}
Both files are inside the http {} block. You can therefore place any nginx directives valid at this level: map, geo, upstream, limit_req_zone, limit_conn_zone, additional proxy_cache_path, log_format, complete server {}, etc.
⚠️ You CANNOT put directives that go at the
mainlevel (abovehttp {}) here — e.g.,worker_processes,worker_rlimit_nofile,events {}. These directives are managed by WSA at the top ofnginx.confand cannot be overridden via these files.
2. When to use pre_virtual_host.conf
This file is included before the vhost list. Your directives here are defined before nginx reads per-account configurations. The ideal place for:
2.1 Define custom map, geo, upstream
These directives are frequently referenced from vhosts. They must therefore be declared before.
# /etc/nginx/pre_virtual_host.conf
# Custom map to identify mobile visitors
map $http_user_agent $is_mobile {
default 0;
"~*Mobile|Android|iPhone" 1;
}
# Upstream for a specific application service
upstream backend_api {
server 10.0.0.42:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.43:8080 backup;
keepalive 16;
}
2.2 Define custom rate-limiting zones
# Special limit for a greedy public API
limit_req_zone $binary_remote_addr zone=api_strict:10m rate=10r/s;
These zones can then be used in post_virtual_host.conf or in a custom server {}.
2.3 Define a custom log_format
log_format custom_combined
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" '
'$upstream_cache_status $request_time';
3. When to use post_virtual_host.conf
This file is included after all vhosts. The ideal place for:
3.1 Add a complete server {}
For example, a private monitoring endpoint or a proxy to a third-party application service:
# /etc/nginx/post_virtual_host.conf
# nginx status endpoint (Prometheus, Grafana, ...)
server {
listen 127.0.0.1:8889;
server_name _;
location /nginx-status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
3.2 Proxy to an external service
# Webhook service hosted separately
server {
listen 443 ssl;
server_name webhook.example.com;
ssl_certificate /etc/letsencrypt/live/webhook.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/webhook.example.com/privkey.pem;
location / {
proxy_pass http://backend_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
4. Edit procedure
4.1 Step by step
-
Edit the file with your favorite editor:
nano /etc/nginx/pre_virtual_host.conf # or vim /etc/nginx/post_virtual_host.conf -
Test the configuration before reloading:
nginx -tIf the output says "syntax is ok" and "test is successful", you're good. Otherwise, the error indicates exactly the line to fix.
-
Reload nginx to apply:
/etc/wsa/wsa --reload-nginx # or systemctl reload nginx
Hot reload doesn't interrupt active connections.
4.2 What happens at the next WSA rebuild?
Your modifications persist — WSA never touches pre_virtual_host.conf or post_virtual_host.conf after initial installation. The regeneration of nginx.conf includes these files as is.
5. Warnings
5.1 A syntax error blocks all of nginx
An invalid directive in these files makes nginx -t fail, and therefore blocks ALL subsequent reloads. nginx continues running with the old config but no WSA change can take effect.
Always test with nginx -t before reloading.
5.2 No conflict with WSA vhosts
If you define a server { listen 80; server_name example.com; ... } that overlaps an existing cPanel vhost, nginx shows a warning at startup and uses the first server encountered (usually WSA's, because pre_ and post_ are outside the conf.d/ subfolder).
To avoid surprises, prefix your server_name or use a different port:
# Good: unique name
server { server_name internal-monitoring.example.com; ... }
# Good: different port
server { listen 127.0.0.1:9999; ... }
# To avoid: collision with a cPanel vhost
server { listen 80; server_name example.com; ... }
5.3 No redundant proxy_cache_* directives
WSA already defines 3 named cache zones (wsa_dynamic, wsa_cssjs, wsa_static) — don't use these names in your code. If you want your own nginx cache for a custom service, choose a unique name:
proxy_cache_path /var/cache/nginx/monitoring_cache
levels=1:2
keys_zone=monitoring:10m
max_size=100m
inactive=1d;
5.4 Backup before modification
Always back up before a big modification:
cp /etc/nginx/pre_virtual_host.conf /etc/nginx/pre_virtual_host.conf.bak
cp /etc/nginx/post_virtual_host.conf /etc/nginx/post_virtual_host.conf.bak
In case of problem, rollback is immediate:
cp /etc/nginx/pre_virtual_host.conf.bak /etc/nginx/pre_virtual_host.conf
nginx -t && systemctl reload nginx
6. Complete examples
6.1 Basic authentication on a subdomain
# /etc/nginx/post_virtual_host.conf
server {
listen 443 ssl;
server_name admin.example.com;
ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem;
# HTTP Basic auth on top of the app
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/htpasswd;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Creation of the htpasswd file:
yum install httpd-tools # or dnf
htpasswd -c /etc/nginx/htpasswd admin
chown nginx:nginx /etc/nginx/htpasswd
chmod 640 /etc/nginx/htpasswd
6.2 HTTP → HTTPS redirect for an external domain
# /etc/nginx/post_virtual_host.conf
server {
listen 80;
server_name external.example.com;
return 301 https://main.example.com$request_uri;
}
6.3 Public health-check endpoint
# /etc/nginx/post_virtual_host.conf
server {
listen 80;
server_name health.example.com;
location /health {
access_log off;
add_header Content-Type text/plain;
return 200 "OK\n";
}
}
7. Troubleshooting
7.1 "nginx: [emerg] ... in /etc/nginx/pre_virtual_host.conf:42"
Syntax error at line 42 of the file. Read the full message from nginx -t for details.
7.2 "conflicting server name 'example.com' on 0.0.0.0:443"
One of your server_names overlaps a cPanel vhost. Use a unique subdomain or a different port.
7.3 WSA configuration seems not to apply
Check that your modifications in pre_/post_virtual_host.conf don't declare a cache zone or map that overrides WSA values. Renaming the zone usually resolves the conflict.
7.4 See the assembled final configuration
# Show the main nginx.conf (generated by WSA)
cat /etc/nginx/nginx.conf
# See how your files are included
grep -n "include.*virtual_host" /etc/nginx/nginx.conf
8. Further reading
- Command line —
nginx -tcommand (via--reload-nginx) and--rebuild-forced. - WHM nginx configuration — The options exposed by WSA often suffice; use the manual files only for what isn't surfaced in the UI.
- Official nginx documentation: nginx.org/en/docs.