# Full Screen Interface

> Manage pxShield from an SSH session with its full screen interface: blocked requests, false positives, WAF rules per site, exclusions, bypass IPs, trusted proxies, cache, server settings and license. The way to manage the WAF on a server without a control panel.

Source: https://www.pyxsoft.com/docs/pxshield/pyxsoft-waf-full-screen-interface
Updated: 2026-11-10

---

On a server with cPanel you manage pxShield from its WHM plugin. On a server **without a control panel** — nginx, Apache or Caddy on plain Linux — you manage it from the terminal: the `pxshield` command opens a full screen interface over SSH, with the same settings the WHM plugin has. It comes with the `pxshield` package, so every server has it, with or without a panel.

![Summary screen of the pxShield full screen interface: blue window with a double frame, menu bar File, View, Help at the top with the hostname and the time; the service running, a valid license, 6 sites with 2 of them with modified rules, 214 blocked requests in 24 hours and 4,128 in 30 days, the last block 3 minutes ago; below, the latest blocked requests with their time, site, visitor IP and country, rule and request, and the function keys at the bottom](https://www.pyxsoft.com/_astro/pxshield-tui-summary.C82uZBjd.png)

## Opening it

Connect to the server over SSH as root and run:

```bash
pxshield
```

It must run as root, and the pxShield service must be running (`systemctl start pxshield`). Press `F10` or `q` to quit.

The screen is built for a terminal of at least 80 columns and 24 lines, and it adapts to a larger one. Every change you make is saved right away; there is no separate "save" step.

> **Keys that do not reach the program**
>
> Some terminals keep function keys for themselves (`F1` and `F10` in GNOME Terminal; on macOS they need `fn`). Every function key also works with its digit: `1` to `9` for `F1` to `F9`, and `0` for `F10`. When the keys of a screen do not fit, the bar at the bottom shows them that way (`7All sites`).

## Moving around

The interface has five screens. `Alt+1` to `Alt+5`, or the **View** menu, switch between them:

| Key | Screen |
|---|---|
| `Alt+1` | **Summary**: the state of the WAF and the latest blocked requests |
| `Alt+2` | **Blocked requests**: every request the WAF stopped, with a filter |
| `Alt+3` | **Sites**: the websites of the server, and for each one its rules, exclusions, bypass IPs, proxies and cache |
| `Alt+4` | **Server**: the settings of the whole server, and the restart of the service |
| `Alt+5` | **License** |

These keys work on every screen:

| Key | What it does |
|---|---|
| `F1` | Shows the keys, with the ones of the current screen |
| `F5` | Refreshes now (the screens also refresh by themselves every few seconds) |
| `F9`, or `Alt` and the first letter of a menu | Opens the menu bar: `Alt+F` File, `Alt+V` View, `Alt+H` Help. The arrows move through the menus, `Enter` runs an item, `Esc` closes |
| `Esc` | Closes a menu or a dialog, or goes back from a request or a site |
| `F10` or `q` | Quits |

The bar at the bottom always shows the function keys of the screen you are on. Actions that weaken the protection — switching a rule off, removing an IP, restarting — ask first; the dialog starts on **Cancel**, so pressing `Enter` by mistake does nothing.

The mouse works too: a click on a menu, a key at the bottom, a button or a tab runs it; in a list, a click selects a row and a double click opens it; on the Summary, a click on a line or on a request opens its screen. To select text with the mouse, hold `Shift`.

## Summary

The Summary shows whether the service is running, the license, how many websites pxShield protects (and how many have rules that differ from the defaults), the requests blocked in the last 24 hours and the last 30 days compared with the 30 days before, and when the last one was blocked. When a server-wide setting is waiting for a restart, a line says so.

Below, the latest blocked requests. Click one to see it, or press `F3` to open the full list. `F4` opens the sites.

If the service is not running, the Summary says **Not reachable** with the reason, and keeps trying every few seconds; it comes back by itself once the service is up.

## Blocked requests and false positives

![Blocked requests screen: a line Showing every site with a filter button, and a table of blocked requests with their time, site, visitor IP and country, the rule in red and the request, such as a SQL injection in product.php, a POST to xmlrpc.php, a GET of .env and of .git/config; at the bottom the position in the list, 1-13 of 4,128](https://www.pyxsoft.com/_astro/pxshield-tui-blocked.BR-8Ar20.png)

**Blocked requests** lists every request the WAF stopped, newest first, 100 at a time. `F7` and `F8` go to the previous and the next page.

`F3` filters the list by site, visitor IP, rule (such as `SQL-001`) or country (a two-letter code, such as `US`); `F4` shows everything again. The filter matches exact values.

`Enter` — or a double click — opens a request: the site, the visitor and its country, the rule that blocked it, the request line, its headers and the start of its body. `Esc` or `F3` go back to the list.

### Allowing a false positive

When a legitimate request was blocked — a plugin saving its settings, an API call, an upload of your own — open it and press `F2`:

![The Allow dialog over a blocked request: XSS-002 will no longer apply on example.com to the URLs that start with the prefix /wp-admin/admin-ajax.php, in an editable field, with the buttons Allow and Cancel](https://www.pyxsoft.com/_astro/pxshield-tui-allow.TY_NWJsl.png)

The dialog proposes the path of the request, without its query string. Leave it, or shorten it to cover more URLs (for example `/wp-admin/` instead of `/wp-admin/admin-ajax.php`), and press **Allow**. From then on, that rule does not apply to the URLs of that site that start with the prefix; every other rule still does, and the rule still applies to the rest of the site and to every other site.

This adds an exclusion, which you can review or remove later in the **Exclusions** tab of the site. See [WAF Exceptions](https://www.pyxsoft.com/docs/pxshield/pyxsoft-waf-exceptions) for how exclusions work.

> **Prefer an exclusion to switching a rule off**
>
> An exclusion opens a hole only where the false positive happens. Switching the rule off removes that protection from the whole site.

## Sites

**Sites** lists the websites pxShield protects. It finds them in the configuration of the web server (nginx, Apache or Caddy); `www.example.com` and `example.com` are one site. The **Rules** column says `modified` when the site has rules that differ from the defaults.

After you add a website to the web server, reload the web server: pxShield picks it up. `Enter` opens a site.

A site opens in five tabs. `Tab` (or `F6`) goes to the next one, `Shift+Tab` to the previous one, and a click on a tab opens it. Changes to a site apply within a minute; the service does not need a restart.

### Rules

![The Rules tab of example.com: the rules grouped by category, Protocol violations, Bad bots, SQL Injections, XSS Attacks; each one with a box, [x] in green when it is on and [ ] in red when it is off, its id and what it protects against; STD-001, STD-004 and STD-005 marked always on, STD-003 under the bar marked changed, and its description at the bottom](https://www.pyxsoft.com/_astro/pxshield-tui-site-rules.BBWkvF1J.png)

Every rule of the WAF, grouped by what it protects against. `[x]` is on, `[ ]` is off. The panel at the bottom explains the rule under the bar.

| Key | What it does |
|---|---|
| `Space`, `Enter` or `F2` | Switches the rule under the bar on or off. Switching it off asks first |
| `F7` | Gives the rule under the bar the same state on **every** site (it asks first) |
| `F8` | Puts every rule of the site back to its default (it asks first). Rules you switched on are switched off again |

**changed** marks a rule whose state differs from its default. **always on** marks a rule that protects the server itself, such as the one against malformed requests: it cannot be switched off.

### Exclusions

![The Exclusions tab of example.com: a table with the URL prefix, the rules, the methods and the IPs of each exclusion; /wp-admin/admin-ajax.php excludes XSS-002 for all methods and IPs, and /api/import excludes SQL-002 and UPL-002 only for POST requests from 203.0.113.10](https://www.pyxsoft.com/_astro/pxshield-tui-site-exclusions.CKciXghO.png)

The exclusions of the site: the rules that do not apply to the URLs that start with a prefix. An exclusion can also be limited to some HTTP methods or some visitor IPs.

- `F2` adds one. Give the URL prefix (it starts with `/`), the rule ids separated by commas (`XSS-002,SQL-002`), and optionally the methods (`POST`) and the IPs (exact addresses, not ranges). Leave methods and IPs empty to match all of them.
- `F8` or `Delete` removes the exclusion under the bar (it asks first).

### Bypass IPs

IP addresses or CIDR ranges (`203.0.113.0/24`) that skip every WAF rule on this site. Use it for your own office, a monitoring service or a trusted integration, never for visitors. `F2` adds one, `F8` or `Delete` removes the one under the bar.

The IPs of the [server-wide bypass](#server) also skip the WAF on every site.

### Proxies

When a site is behind a reverse proxy — a CDN, a load balancer — every request comes from the proxy, not from the visitor. 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** screen see the real visitor.

- `F2` adds a proxy (an IP or a CIDR range), `F8` or `Delete` removes the one under the bar.
- `F4` sets **Cloudflare** for this site: **as the server** (the default), **on** or **off**. On trusts the Cloudflare edges as proxies of this site; off stops trusting them, for a site that is not behind Cloudflare even if the server says so.

The panel at the bottom shows the proxies trusted for the whole server, which apply to this site too.

> **Only list real proxies**
>
> A visitor can write anything in `X-Forwarded-For`. The WAF only believes it when the request comes from an address listed as a proxy, so list only the proxies you control or trust, never a visitor or a whole provider network.

### Cache

The cache settings of the site:

- **Pages**: off; **manual**; or **wordpress**, where the Pyxsoft WordPress plugin says which pages may be cached.
- **WebP**, **Minify JS**, **Minify CSS**: on, off, or default, which follows the server.

`F2` or `Enter` changes them. `F4` purges one URL, or every URL that starts with a prefix when it ends in `*` (`/blog/*`). `F7` purges the whole cache of the site (it asks first).

The cache only works when its engine is enabled in `/etc/pxshield.ini` (`CacheStaticFiles`, `CacheDynamicFiles`); both are off by default.

## Server

![Server screen: Max POST size 128 MB, Gzip on and Cloudflare on, the WAF bypass with 203.0.113.10 and the trusted proxies with 198.51.100.7; the panel at the bottom explains the setting under the bar, and the keys Bypass IP, Proxy and Restart](https://www.pyxsoft.com/_astro/pxshield-tui-server.CSnmEoKo.png)

The settings of the whole server:

| Setting | What it is | When it applies |
|---|---|---|
| **Max POST size** | The largest request body the WAF accepts, from 1 to 2048 MB. Larger uploads are refused | After a restart |
| **Gzip** | Compresses the answers on the fly | After a restart |
| **Cloudflare** | Trusts the Cloudflare edges as proxies on every site that does not say otherwise | Right away |
| **WAF bypass** | IPs and ranges that skip every WAF rule on every site | After a restart |
| **Trusted proxies** | Reverse proxies of every site (see [Proxies](#proxies)) | Right away |

`Enter` changes the setting under the bar. `F2` adds a bypass IP, `F4` a trusted proxy, and `F8` or `Delete` removes the IP under the bar.

`F7` restarts the service, which applies the settings marked *after a restart*. While one of them is waiting, the panel at the bottom and the Summary say so. A restart cuts the connections in progress for a moment, so do it at a quiet time.

## License

**License** shows whether the license is valid, until when, its code (only its last characters) and its holder.

- `F2` sets a license code. It is typed hidden, so it does not show on a shared screen.
- `F3` starts the free trial, when the server can still use one.

## Working alongside WHM

On a server with cPanel, the WHM plugin and this interface change the same settings. Each change re-reads the current settings just before saving, so a change made from WHM a moment earlier is not overwritten. If both are open, `F5` shows the latest state.

## Terminal tips

- The interface draws its frames with line characters even when the locale of the server is `C`, as on a minimal VPS. If your terminal shows them wrong, run `PXSHIELD_ASCII=1 pxshield` to draw them with plain ASCII.
- Without a terminal — from cron, a script or a pipe — `pxshield` without arguments prints its usage instead of opening the interface. Every action of the interface is also a command for scripts: see [Command Line](https://www.pyxsoft.com/docs/pxshield/pyxsoft-waf-command-line).
- Text that comes from visitors (URLs, headers, bodies) is shown with its control characters escaped (`\x1b`), so a crafted request cannot change your terminal.

## Troubleshooting

**`pxshield: it must run as root`** — run it as root, or with `sudo pxshield`.

**`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 it only talks to it 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.

**A site is missing from Sites** — 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`); pxShield picks up the change.
