# Protect an existing SSL site

> Put an already-hosted site (nginx, Apache, Caddy — any app) behind L7 Shield: keep your server as the private origin, cut DNS over, verify.
>
> Canonical: https://xdp.network/docs/products/protect-existing-site · Updated 2026-08-18

You can put a site that is already live with its own HTTPS — nginx + certbot, Apache,
Caddy, any app — behind L7 Shield without moving it. Your server stays as the private
origin; the edge terminates public TLS under the same hostname and reverse-proxies to it.

## How it works

The edge node answers `https://<your-hostname>` from the public internet and forwards
traffic to your origin over the origin's own HTTPS (or plain HTTP on a private network).
Visitors see no change; the origin keeps its own certificate for the edge→origin hop.
Going live is one DNS change: an A record pointing the hostname at the node IP — applied
for you when the zone is on your connected Cloudflare account, manual otherwise.

The edge sends the real visitor IP in the standard `X-Forwarded-For` header, which is
exactly what `real_ip_header` (nginx), `mod_remoteip` (Apache) and `trusted_proxies`
(Caddy) consume.

## Before you start

Have these ready:

- **The site's existing certificate + key** if browsers must keep seeing that exact cert.
  On a certbot host they are `/etc/letsencrypt/live/<host>/fullchain.pem` and
  `privkey.pem`. Let's Encrypt renews every ~90 days and the edge does not renew a pasted
  cert for you — re-upload after each renewal. For testing (or whenever DNS is proxied
  through Cloudflare, which hides the edge cert anyway) self-signed on the edge is fine.
- **The origin URL**: `https://<your-domain-or-origin-ip>` — keep the origin's own cert
  valid. Use `http://` only for same-box or private-network origins.

## Connect the site

Run **Connect a domain** on the L7 Shield product page (the full wizard is covered in
[L7 Shield](/docs/products/l7-shield)). For an existing site:

1. **Backends** — your origin URL from above.
2. **SSL certificate** — **Paste my own** with the fullchain + key, or self-signed.
3. **Protection** — leave **WebSockets** on (default) so live consoles, chats and
   realtime dashboards keep working; turn it off only for sites that never upgrade.
4. **DNS** — leave the cutover on for an automatic proxied A record, or turn it off and
   point the record yourself.

## Lock the origin down

Once DNS points at the edge, the origin should trust proxy headers only from the node
and stop answering direct traffic. The site's detail page shows these with your node IP
filled in:

```nginx title="nginx — inside the server block"
set_real_ip_from <node IP>;
real_ip_header X-Forwarded-For;
```

```apache title="apache — mod_remoteip"
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy <node IP>
```

```caddy title="caddy — inside reverse_proxy"
trusted_proxies <node IP>
```

Firewall hint: `ufw allow from <node IP> to any port 443 proto tcp` — then drop public
443 so attackers can't bypass the shield by hitting the origin directly.

## Verify the chain

The site detail page carries a **Finish setup** card until everything passes. **Run
verification** probes the live chain from the platform: DNS resolution, an HTTPS request
(reporting the status code and TLS days-remaining), and a WebSocket upgrade. All green
collapses the card to an "origin protected" state; any failure says exactly which hop
broke.

## Case study: a Pterodactyl panel

A panel at `gp.altis.host` on nginx + certbot + php-fpm needs exactly one changed line
in its server block. The panel already restores visitor IPs from a local proxy:

```nginx title="before"
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
```

```nginx title="after"
set_real_ip_from <node IP>;
real_ip_header X-Forwarded-For;
```

Everything else — the certbot `ssl_certificate` paths under
`/etc/letsencrypt/live/gp.altis.host/`, the `fastcgi_pass` to the php-fpm socket — stays
as-is, because the edge talks to nginx the same way the local proxy did.

The panel's WebSocket console is **not** affected: the browser opens it straight to the
wings daemon on the game node, not through the panel vhost. Panel protection is pure
HTTPS — nothing to change on wings.

## Next steps

- [L7 Shield](/docs/products/l7-shield) — the full connect wizard, tabs and analytics.
- [Cloudflare](/docs/products/cloudflare) — connect the account that drives DNS cutover.
- [L4 Tunnel](/docs/products/l4-tunnel) — protect game servers and other raw TCP/UDP.
