Luviner
ShieldWebsite protection LynxServer monitoring
DocsGuides and API reference
ShieldWebsite protection LynxServer monitoring
About Contact IT Log in Start free
Docs
Getting Started CSV Format Sensor to CSV Supported Hardware Firmware Integration
Lynx Monitoring
Lynx Quick Start
Shield
Shield

Shield Documentation

Shield sits in front of your site, on your own server, and decides who gets in: customers and search engines go through, bots, scrapers, attacks and traffic waves are stopped. It installs with one command and checks by itself that every site answers as before.

1. How Shield works with your site

A lightweight web server (nginx, or Traefik if you already use it) receives the visitors and asks Shield about every page before handing it to your site. Images, CSS and JavaScript skip Shield. Your application is not modified and does not need to know Shield exists.

  • Traffic waves. Shield learns how many new visitors your site normally receives. When far more arrive at once, unknown visitors go through a short automatic check in the browser (about half a second, then the page opens by itself). Visitors already let in carry a pass and do not notice anything.
  • Attacks. Requests for secret files, known exploit paths and login floods are refused before they reach the application.
  • Bots. Scrapers posing as browsers, fake search engines and greedy crawlers are recognised by their behaviour.
  • Never in the way of search engines. Verified search engines, link previews, robots.txt and sitemaps are never stopped.

Whatever runs behind the web server (PHP, Python, Java, Node…) does not matter.

2. Requirements

Receives the visitors todayInstall
Apache on Debian or UbuntuFully automatic: install, checks, rollback
nginxThe package holds the lines to include in your server blocks
Traefik (Docker)The package holds Shield's container and the labels for your routers

Plus: Docker, Python 3.8 or newer, and an administrator (sudo) for the install step. Shield uses about 50 MB of memory.

3. Install

# 1. Download the installer (standard library only, nothing to pip install) curl -fsSLO https://luviner.com/downloads/shield-setup.py # 2. Pull Shield docker pull luviner/shield:2.4 # 3. Look at the server — read-only, no sudo, changes nothing python3 shield-setup.py analyze # 4. Answer a few questions and write the install package python3 shield-setup.py plan # 5. Install (Apache front) sudo ./ward-setup-*/install.sh

analyze reports what receives the visitors, which sites the server hosts, what runs behind them and anything that blocks the install. plan asks only what it cannot detect:

  • which sites to protect (default: every site serving an application, not the redirect-only domains);
  • online payments (PayPal, Stripe…), so their notifications always get through;
  • other addresses called by external servers: couriers, ERP, marketplaces;
  • addresses always let through: the server itself, your office;
  • start in observe or enforce mode (see section 5).

What install.sh does (Apache)

  1. Checks the server is as analysed and Shield's image is available.
  2. Records how every site answers: status, redirect target and certificate of every domain.
  3. Backs up the Apache, nginx and certificate renewal settings.
  4. Installs nginx without starting it, writes and tests its configuration, starts Shield.
  5. Switches over: Apache keeps all its sites, redirects and certificates and moves to 127.0.0.1; nginx takes the public addresses. A few seconds without service.
  6. Checks every site answers exactly as before, and that your site still sees each visitor's real address. Any difference: automatic rollback.
  7. Tests the renewal of each certificate and makes nginx reload them after every renewal.
To undo, at any time: sudo ./ward-setup-*/rollback.sh puts the Apache, nginx and certificate settings back exactly as they were, stops nginx and Shield, and checks Apache is back on its ports.

nginx already in front

Start Shield with start-ward.sh from the package, copy ward-http.conf to /etc/nginx/conf.d/ and ward-server.conf to /etc/nginx/snippets/, then add one line in each protected server block:

include snippets/ward-server.conf;

Then sudo nginx -t && sudo systemctl reload nginx. If Shield stops, nginx lets visitors in.

Traefik

start-ward.sh starts Shield on Traefik's network. Add the labels from traefik-labels.txt to the protected sites' containers and recreate them. Shield is used as a ForwardAuth middleware.

With Traefik, if Shield stops the protected sites answer 500 until it restarts (Shield restarts by itself). With Traefik older than 3.1 the visitor pass is given only by the check page.

4. Your server after the install

  • docker ps shows the ward container, listening on 127.0.0.1 only. It restarts by itself.
  • Apache listens on 127.0.0.1:80/443: do not put it back on all addresses while nginx is in front.
  • A new HTTPS domain configured in Apache must also be added to nginx (/etc/nginx/sites-available/ward-front). Plain-HTTP and redirect-only domains need nothing.
  • Apache's logs keep the visitor's real address, so fail2ban and IP rules in .htaccess keep working.
  • mod_evasive is turned off by the install: it counts requests per connection, so behind nginx every visitor would look like one. nginx and Shield take over its job.

5. Observe, then enforce

Shield starts in observe mode: traffic waves and attacks are stopped, every other bot is only noted. After a few days, read the status (section 6). When the list contains no customers, switch to enforce:

sudo sed -i 's/^WARD_GATE_MODE=.*/WARD_GATE_MODE=enforce/' /etc/ward-setup/ward.env sudo docker rm -f ward && sudo docker run -d --name ward --restart unless-stopped \ -p 127.0.0.1:9741:9741 -p 127.0.0.1:9742:9742 -v ward_data:/app/models \ --env-file /etc/ward-setup/ward.env --memory 1g luviner/shield:2.4

Visitor passes and what Shield learnt are kept in the ward_data volume across restarts.

6. Status

curl -s http://127.0.0.1:9741/gate/status
FieldMeaning
modeobserve or enforce
counts.requestsPages Shield was asked about
counts.trustedRequests from always-trusted addresses
counts.<reason>Refusals by reason; observed: means noted, not refused
flood.activeA traffic wave is in progress
flood.new_visitors_per_min / threshold_per_minNew visitors now, and where the wave alarm starts
flood.past_floodsRecent waves: start, end, peak
recent_refusalsThe latest refusals with address, page and reason

7. Dashboard and alerts on luviner.com (optional)

Shield can report to your Luviner account, so you see every server in one page and get an email (and a Telegram message, if you connect it) when a traffic wave starts and ends.

  1. Sign in at luviner.com, open Shield and generate the connection token. One token serves all your servers.
  2. New install: paste it when shield-setup.py plan asks for it. Shield already installed: add WARD_REPORT_TOKEN=… to /etc/ward-setup/ward.env and recreate the container (section 5).
What leaves your server: pages checked, refusals by reason, the wave state and its threshold, past waves (start, end, peak), and attack signatures: the family and path of attack attempts (such as /.env), with numbers and tokens masked. Every minute, and at once when a wave starts or ends. No visitor address, no visited page, no header. The connection is outbound only: no port is opened. If luviner.com cannot be reached, protection is not affected.

Community plan: connecting to your Luviner account is the condition of the free plan. The numbers and attack signatures help Shield learn new attacks for every site. On the paid plans the connection is optional and everything can stay on your server.

8. Configuration

Settings live in /etc/ward-setup/ward.env; after a change, recreate the container as in section 5.

VariableDefaultDescription
WARD_GATE_MODEenforce (install: observe)observe or enforce
WARD_FLOOD_ACTIONchallengeDuring a wave: challenge unknown visitors, only observe, or off
WARD_TRUSTED_IPS—Addresses or networks always let through, comma-separated
WARD_ALWAYS_ALLOW_PATHSrobots, sitemaps…Pages always served to everyone (payment notifications, webhooks)
WARD_PROBE_ALLOW—Platform paths the site uses legitimately (e.g. wordpress, graphql); set by shield-setup
WARD_DECLARED_BOT_ACTIONallowBots that say who they are (SEO tools, AI crawlers): allow or block
WARD_LOGIN_MAX_ATTEMPTS20Login form submissions per visitor every 15 minutes
WARD_SITE_HOST—Your site's name, set by shield-setup
WARD_REPORT_TOKEN—Luviner account token (section 7); empty: nothing is sent
WARD_NODE_NAMEsite nameHow this server is called in the dashboard

9. API mode

Shield can also be asked directly by your application, without a web server in front: POST /check on port 9741 with the request's details returns allow or block and a reason. Use it for APIs or to add Shield's verdict to your own logic. It does not protect against traffic waves, because the requests have already reached your application.

curl -s -X POST http://127.0.0.1:9741/check -H 'Content-Type: application/json' -d '{ "session_id": "visitor-123", "client_ip": "203.0.113.9", "method": "GET", "path": "/products/shoes", "headers": {"User-Agent": "Mozilla/5.0 ...", "Referer": "https://shop.example/"} }'
EndpointMethodDescription
/checkPOSTVerdict on one request: action, reason, score
/gate/statusGETWaves, refusals and mode (section 6)
/healthGETHealth check
/statsGETOperational statistics
/metricsGETPrometheus metrics

10. Measured on real traffic

Real logs of an Italian B2B shop on Magento, replayed with Shield in front: one week to learn its normal traffic, then the morning a distributed scraper sent 18,560 requests in 5 minutes from 17,416 addresses and took the site down for over an hour.

Without ShieldWith Shield
Wave recognised—after 38 seconds
Requests reaching the site, first 5 minutespeak 122/s1.2/s on average
Connections heldby the site (exhausted)by nginx
False wave alarms in the previous week—0
Customer actions refused (cart, login)—0
Real browsers that saw the check page—207 of 683, once

Since 26 October 2026 Shield protects that site in production.

11. Good to know

  • An attack that saturates the server's internet line needs a network in front (a CDN): no software on the server can stop it. Shield works alongside one.
  • The check page during a wave needs JavaScript. Visitors without it see a message, only during a wave.
  • The visitor pass is a technical security cookie (ward_pass): list it in your cookie policy.
  • nginx listens on the server's addresses found at install time: if they change, run plan again.
  • One Shield serves all the protected sites of a server.
Need help with the install? The Pro and Business plans include a remote assisted install. See the plans or contact us.
Luviner

Website protection and server monitoring. Designed in Italy.

Products

Shield Lynx

Pricing

Shield Lynx

Resources

Docs Research

Company

About Contact
© 2026 Luviner · P.IVA / VAT ID IT02880910340 Terms of Service Privacy Policy End User License Agreement