Command Line
Reference of the pxshield command: status, sites, WAF rules per site, blocked requests and false positives, bypass IPs, trusted proxies, exclusions, cache, license and server settings, from the shell or from scripts.
The pxshield command manages pxShield from the shell. It comes with the pxshield package, so every server has it, with or without a control panel. Every action of the full screen interface is also a command, which makes it the tool for scripts, automation and quick checks over SSH.
It must run as root, and the pxShield service must be running (systemctl start pxshield). Without arguments, on a terminal, it opens the full screen interface; from a script it prints its usage.
pxshield help # the list of commands
pxshield <command> --help # the options of one command
Global options go before the command:
| Option | What it does |
|---|---|
--json |
Prints the answer of the service as JSON, for scripts |
--version |
Prints the version |
-h, --help |
Prints the usage |
Exit codes: 0 ok, 1 error, 2 wrong usage, 3 the license is not valid (status and license).
A site is named by its domain. www.example.com and example.com are the same site, and a name that is not a website of the server is refused: pxshield sites lists them.
Status
pxshield status
Service running
License valid until 2027-11-10
Sites 6 sites, 2 with modified rules
Blocked 214 in 24 h, 4,128 in 30 days (+9% vs the 30 days before)
Last block 3 min ago
When a server-wide setting is waiting for a restart, a Settings line says so. The exit code is 3 when the license is not valid, so a monitoring check can use it:
pxshield status >/dev/null || echo "pxShield needs attention"
Sites
pxshield sites
SITE RULES
blog.example.com default
example.com default
shop.example.com modified
staging.example.net default
store.example.org modified
wiki.example.net default
The websites pxShield protects, read from the configuration of the web server (nginx, Apache or Caddy). modified means the site has rules that differ from the defaults. After adding a website to the web server, reload the web server and pxShield picks it up.
Rules
pxshield rules <site> [show|on|off|reset] [rule ...] [--all] [--yes]
Without an action, it lists every rule of the site and its state:
$ pxshield rules example.com
WAF rules of example.com
Protocol violations
RULE STATE PROTECTS AGAINST
STD-001 on HTTP Protocol violation: Bad request line always on
STD-002 off IP in host header not allowed
STD-003 on Missing User-Agent header changed
STD-004 on Null character in request always on
STD-005 on Path traversal attack in URI always on
SQL Injections
RULE STATE PROTECTS AGAINST
SQL-001 on SQL Injection attempt in GET
SQL-002 on SQL Injection attempt in POST
SQL-003 on Attempts to search/download a .sql file
...
changed marks a rule whose state differs from its default; always on marks a rule that protects the server itself and cannot be switched off.
on and off switch rules. Give rule ids, or a category to switch all its rules at once (STD, BOT, SQL, XSS, APP, WP, UPL, BF, DOS, IP); separate several with spaces or commas. Case does not matter.
pxshield rules example.com on XSS-001 XSS-002 # two rules
pxshield rules example.com on XSS # every XSS rule
pxshield rules example.com off STD-003 --yes # no question, for a script
pxshield rules example.com on SQL --all # the SQL rules, on every site
pxshield rules example.com reset # every rule back to its default
| Option | What it does |
|---|---|
--all |
Applies the change to every site of the server, not only to the one named |
--yes |
Does not ask. Switching rules off and reset ask first on a terminal, and refuse without one unless --yes is given |
reset also switches off the rules you had switched on, such as the XSS rules, which are off by default. Changes apply within a minute; the service does not need a restart.
Blocked requests
pxshield events [list|show <id>|allow <id>] [options]
pxshield events lists the requests the WAF blocked, newest first:
$ pxshield events --limit 5
ID TIME SITE IP CC RULE REQUEST
41208 11-10 11:57:00 shop.example.com 185.220.101.34 DE SQL-001 GET /product.php?id=1' UNION SELECT user,pass F…
41207 11-10 11:50:00 example.com 45.155.205.211 NL XSS-002 POST /wp-admin/admin-ajax.php
41206 11-10 11:43:00 blog.example.com 103.152.118.20 IN WP-001 POST /xmlrpc.php
41205 11-10 11:36:00 example.com 193.41.206.82 RU APP-008 GET /.env
41204 11-10 11:29:00 store.example.org 45.148.10.95 NL APP-007 GET /.git/config
5 of 4,128. --offset 5 shows the next ones.
| Option | What it does |
|---|---|
--site <site> |
Only the requests to this site |
--ip <address> |
Only the requests from this visitor IP |
--rule <rule> |
Only the requests blocked by this rule, as SQL-001 |
--country <country> |
Only the requests from this country, as a two-letter code (US) |
--limit <n> |
At most n requests, up to 1000 (50 by default) |
--offset <n> |
Skips the first n, to read the next page |
The filters match exact values and can be combined:
pxshield events --site example.com --rule XSS-002
pxshield events --ip 185.220.101.34 --limit 200
show prints one request in full: the visitor, the rule, the request line, its headers and the start of its body.
$ pxshield events show 41207
Event 41207
Time 2026-11-10 11:50
Site example.com
Visitor 45.155.205.211 NL
Rule XSS-002 XSS Injection attempt in POST
Request POST /wp-admin/admin-ajax.php HTTP/1.1
Host example.com
Headers
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Content-Type: application/x-www-form-urlencoded
Body
action=save&content=%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E
A false positive? pxshield events allow 41207
Text written by visitors (URLs, headers, bodies) is printed with its control characters escaped (\x1b), so a crafted request cannot change your terminal.
Allowing a false positive
allow stops the rule that blocked a request from applying to that URL of its site. It adds an exclusion for the path of the request, without its query string:
$ pxshield events allow 41207
XSS-002 no longer applies to example.com/wp-admin/admin-ajax.php.
--url sets a shorter prefix, to cover more URLs:
pxshield events allow 41207 --url /wp-admin/
Every other rule still applies to those URLs, and the rule still applies to the rest of the site.
Exclusions
pxshield exclusions <site> [list|add|remove <n>] [options]
The exclusions of a site: rules that do not apply to the URLs that start with a prefix, optionally only for some HTTP methods or some visitor IPs.
$ pxshield exclusions example.com
# URL PREFIX RULES METHODS IPS
1 /wp-admin/admin-ajax.php XSS-002 all all
2 /api/import SQL-002,UPL-002 POST 203.0.113.10
pxshield exclusions example.com add --url /wp-admin/admin-ajax.php --rules XSS-002
pxshield exclusions example.com add --url /api/import --rules SQL-002,UPL-002 --methods POST --ips 203.0.113.10
pxshield exclusions example.com remove 2
Option of add |
What it does |
|---|---|
--url <prefix> |
The URL prefix, starting with /. Required |
--rules <ids> |
The rule ids, separated by commas. Required |
--methods <methods> |
Only these HTTP methods, separated by commas. All by default |
--ips <ips> |
Only these visitor IPs, separated by commas: exact addresses, not ranges. All by default |
When an exclusion with the same prefix, methods and IPs exists, add adds the rules to it instead of creating another one. remove takes the number shown by list; list again before removing if someone else may have changed them. See WAF Exceptions for how exclusions are matched.
Bypass IPs
pxshield bypass [list|add|remove] [--site <site>] [ip ...]
IP addresses and CIDR ranges that skip every WAF rule: on the whole server, or with --site on one site. Use it for your own office, a monitoring service or a trusted integration, never for visitors. Separate several IPs with spaces or commas.
pxshield bypass # the server-wide list
pxshield bypass add 203.0.113.10 # on every site (asks first)
pxshield bypass add 198.51.100.0/24 --site example.com --yes
pxshield bypass remove 203.0.113.10
add asks first on a terminal, and refuses without one unless --yes is given. The server-wide list applies when the service restarts (pxshield restart); the list of a site applies within a minute. The IPs of the server-wide list skip the WAF on every site, also when the list of the site does not name them.
Trusted proxies
pxshield proxies [list|add|remove|cloudflare] [--site <site>] [ip ...|on|off|default]
When the sites are behind a reverse proxy — a CDN, a load balancer — every request comes from the proxy. List the proxy here and the WAF takes the visitor IP from the X-Forwarded-For header of the requests that come from it, so the WAF and the blocked requests see the real visitor.
pxshield proxies add 198.51.100.7 # for every site
pxshield proxies cloudflare on # trust the Cloudflare edges, on every site
pxshield proxies add 192.0.2.20 --site example.com # one more, only for this site
pxshield proxies cloudflare off --site example.com # this site is not behind Cloudflare
pxshield proxies cloudflare default --site example.com # follow the server again
pxshield proxies --site example.com # what this site trusts
$ pxshield proxies --site example.com
Trusted proxies of example.com
192.0.2.20
Also trusted, from the whole server
198.51.100.7
Cloudflare on, as the server
A site adds proxies to the server-wide ones; it cannot drop them. Its Cloudflare setting replaces the server’s, both ways, or follows it with default. Changes to the server-wide proxies and Cloudflare apply at once; the ones of a site within a minute.
Cache
pxshield cache <site> [show|dynamic|webp|minify-js|minify-css|purge] ...
$ pxshield cache example.com
Cache of example.com
Pages off
WebP default
Minify JS default
Minify CSS default
pxshield cache example.com dynamic on # cache pages, in the mode it had (manual the first time)
pxshield cache example.com dynamic wordpress # on; the Pyxsoft WordPress plugin says what may be cached
pxshield cache example.com dynamic manual # on, manual mode
pxshield cache example.com dynamic off
pxshield cache example.com webp on # also minify-js and minify-css: on, off or default
pxshield cache example.com purge # empties the cache of the site
pxshield cache example.com purge /blog/* # a URL, or every URL that starts with a prefix ending in *
default follows the server. The cache only works when its engine is enabled in /etc/pxshield.ini (CacheStaticFiles, CacheDynamicFiles); both are off by default.
License
pxshield license # the state of the license
pxshield license set # asks for the code
pxshield license trial # starts the free trial, when the server can still use one
$ pxshield license
License valid until 2027-11-10
Code ••••••D-91BX
Customer Example Hosting
Without a code, set reads it from the standard input, so it does not show in the list of processes, where every user of the server could see it while the command runs:
pxshield license set < /root/pxshield-license.txt
pxshield license set <code> also works, for a quick change on a server only you use. The exit code is 3 while the license is not valid.
Server settings
pxshield config [show|max-post-size <MB>|gzip on|off]
$ pxshield config
Max POST size 128 MB
Gzip on
WAF bypass 1 IP (pxshield bypass)
Trusted proxies 1 proxy (pxshield proxies)
pxshield config max-post-size 256 # the largest request body the WAF accepts, 1 to 2048 MB
pxshield config gzip off # compression of the answers on the fly
pxshield restart # applies them
The POST size, gzip and the server-wide bypass apply when the service restarts. pxshield restart restarts it; the connections in progress are cut for a moment, so do it at a quiet time.
Scripts
Every command takes --json before its name and prints the answer of the service as JSON:
pxshield --json events --site example.com --limit 100 | jq -r '.items[].remoteIP' | sort | uniq -c | sort -rn
pxshield --json sites | jq -r '.[] | select(.modified) | .domain'
Commands that weaken the protection (rules off, rules reset, bypass add) ask on a terminal; from a script they refuse unless --yes is given, so a mistake in a script does not switch a rule off silently. Run them as root, for example from root’s crontab.
Troubleshooting
pxshield: it must run as root — run it as root, or with sudo.
the pxshield service is not running — start it with systemctl start pxshield; journalctl -u pxshield shows why it stopped.
something that is not the pxshield service listens on its RPC port — pxshield talks to the service on 127.0.0.1:2987, and only when the program listening there belongs to root, as the pxShield service does. Another program, run by another user, was listening on that port, so nothing was sent to it. Find it with ss -ltnp 'sport = :2987', stop it, and start pxShield.
example.com is not a site of this server — pxShield reads the sites from the configuration of the web server. Check that the site is enabled there and reload the web server (systemctl reload nginx, apache2, httpd or caddy).
This page is also available as markdown.