# The Web Server (CoreHttpd)

> CorePanel does not ship Apache or nginx. Every site is served by CoreHttpd, CorePanel's own web server: what it replaces, where its files and logs live, and why it never runs as root.

Source: https://www.corepanel.net/docs/web/
Last updated: 2026-09-02
Part of the CorePanel documentation — https://www.corepanel.net/docs

---

CorePanel does not ship Apache, nginx or LiteSpeed. Every site on the server — and the
panel itself — is served by **CoreHttpd**, the web server CorePanel is built around.

Most of the time that is invisible: sites are configured from the panel and the server
follows. This page is for the moments when it is not invisible — when you go looking for
a vhost file that is not there, when a log is not where you expected it, or when you need
to know exactly what the process serving your customers can and cannot read.

> **Three spellings, one thing**
>
> **CoreHttpd** is the product name. `corehttpd` is the systemd unit, the system user and
> the path prefix. `corepanel-httpd` is the RPM — the name to use with `rpm -q` or `dnf`.
## What it replaces

If you have run a hosting server before, this table is the fastest way in. Nothing in the
left column exists on a CorePanel server.

| On Apache / nginx | On CorePanel |
|---|---|
| A vhost or `server {}` block per site | A site record in the panel; CorePanel writes the server's config itself |
| `httpd -t` / `nginx -t` before a reload | Nothing to validate — there is no configuration language to get wrong |
| `mod_rewrite`, `mod_deflate`, `mod_headers`… | Built into the server; nothing to load |
| A third-party cache, WebP or minify module | [Web optimizations](https://www.corepanel.net/docs/web/optimizations), per site, in the panel |
| certbot, a renewal cron, a deploy hook | [Automatic certificates](https://www.corepanel.net/docs/ssl-certificates), issued and renewed by the server |
| `/var/log/httpd/*` | `/var/log/corehttpd/*`, plus one access log per domain |
| The `apache` / `nginx` user, started as root | The `corehttpd` user, which is never root |
| `.htaccess` | [`.htaccess`](https://www.corepanel.net/docs/web/htaccess) — still read, with a report of what was applied |

## There are no vhost files to edit

CorePanel does not render a configuration file for CoreHttpd to parse. It writes one JSON
site record per site into `/var/lib/corehttpd/sites/<domain>.json` and signals the server
to re-read them. Each file is written to a temporary name and renamed into place, so a
half-written file is never read as live configuration, and the reload is a `SIGHUP`: no
downtime, no dropped connections.

The practical consequence: **those files are not yours to edit.** They are regenerated
from the panel's database whenever anything about the site changes — a new alias, a PHP
version, a certificate, a serving mode — and a hand edit is silently overwritten the next
time that happens. Everything they contain has a control in the panel or in the
[CLI](https://www.corepanel.net/docs/cli).

For anything that a single document root cannot express, the site record carries an
ordered route table — that is what [reverse proxy routes](https://www.corepanel.net/docs/reverse-proxy) are — and
that too is written by the panel.

## It does not run as root

Apache runs as root. So do nginx and LiteSpeed: they start privileged, bind the low
ports, and drop to an unprivileged user for the workers. CoreHttpd never has privileges
to drop. It runs as the unprivileged `corehttpd` user from the first instruction, with
exactly two capabilities granted by its unit:

| Capability | What it is for |
|---|---|
| `CAP_NET_BIND_SERVICE` | Bind ports 80 and 443 as a non-root user |
| `CAP_DAC_READ_SEARCH` | **Read** any document root regardless of owner and mode |

That second one is what lets account homes stay `0700` and account files `0600` with no
POSIX ACLs anywhere. The traditional approach — granting the web server access with
`setfacl` — is fragile, because `tar`, `rsync`, backups, restores and ordinary uploads all
strip ACLs, so the panel has to keep reapplying them forever. CoreHttpd needs none.

The capability is read-only: it bypasses permission checks for reading and traversing,
never for writing. And because it is broad, the real boundary is mandatory access
control — CoreHttpd runs in **its own SELinux domain, `corehttpd_t`**, shipped as a policy
module with the RPM. Not `httpd_t`: a domain scoped to what this server actually does.

```bash
# The web server should show corehttpd_t, not init_t or unconfined_t
ps -eZ | grep corehttpd
```

> **Do not disable SELinux, and do not add NoNewPrivileges**
>
> CorePanel expects enforcing mode; the confinement above is the read boundary. The unit
> deliberately does **not** set `NoNewPrivileges` — under it the kernel refuses the domain
> transition and the server keeps running unconfined, which is strictly worse than the
> hardening the option looks like it is adding. The same applies to any drop-in that
> implies it (`ProtectKernelTunables`, `SystemCallFilter`, `RestrictSUIDSGID`…).
Beyond that, the unit runs with `ProtectSystem=strict` and `ProtectHome=read-only`: the
only paths the server can write are `/var/lib/corehttpd` and `/var/log/corehttpd`.

It also never executes PHP in its own process. PHP runs in a per-account PHP-FPM pool that
CoreHttpd reaches over a Unix socket — see [How PHP runs](https://www.corepanel.net/docs/php/how-php-runs). A
compromised web server is an HTTP front and nothing more; it cannot read a customer's
`wp-config.php`, because only that account's pool ever opens it.

## Protocols, ports and certificates

| | |
|---|---|
| `80/tcp` | HTTP/1.1 — redirects to HTTPS where [Force HTTPS](https://www.corepanel.net/docs/web/https-redirect) is on |
| `443/tcp` | HTTP/1.1 and HTTP/2 over TLS |
| `443/udp` | HTTP/3 over QUIC, advertised to browsers with `Alt-Svc: h3=":443"` |

HTTP/2 and HTTP/3 are on by default and need no per-site setting. Responses carry
`Server: CoreHttpd`, which is the quickest way to confirm from outside which server
answered:

```bash
curl -sI https://example.com | grep -i '^server\|^alt-svc'
```

Certificates are the server's own job: it obtains them from Let's Encrypt on demand,
renews them before expiry, and prefers an uploaded commercial certificate over its own
wherever one has been installed. [SSL/TLS certificates](https://www.corepanel.net/docs/ssl-certificates) covers both paths.

## What it does that a stock server would need modules for

Each of these is part of the same request, in the same process, and each has its own page:

- [Web serving modes](https://www.corepanel.net/docs/web/serving-modes) — what happens to a path that is not a file
- [Force HTTPS](https://www.corepanel.net/docs/web/https-redirect) — per domain, applied only when a certificate exists
- [Web optimizations](https://www.corepanel.net/docs/web/optimizations) — WebP conversion, Early Hints, minification, the dynamic page cache
- [`.htaccess` support](https://www.corepanel.net/docs/web/htaccess) — the rules a site brings with it from cPanel
- [Web application firewall](https://www.corepanel.net/docs/security/waf) — in the server, on every edition
- [Reverse proxy routes](https://www.corepanel.net/docs/reverse-proxy) — publish a local service under a domain
- [Web traffic graphs](https://www.corepanel.net/docs/web-traffic) — requests per minute and latency percentiles, from the server's own counters

## Where everything is

| Path | What it holds |
|---|---|
| `/etc/corehttpd.ini` | The server's own settings — see below |
| `/var/lib/corehttpd/sites/` | One JSON site record per site, written by CorePanel |
| `/var/lib/corehttpd/` | Writable state: certificate cache, WebP and minify cache, the host certificate, the GeoIP database, the WAF event store |
| `/var/log/corehttpd/access.log` | Server-wide access log |
| `/var/log/corehttpd/error.log` | Server errors — the first place to look |
| `/var/log/corehttpd/users/<account>/<domain>.access.log` | One access log per domain |

Per-domain access logs live outside the account's home and are symlinked into
`~/logs`, so the account can read its own traffic without being able to touch the file.
All of them are also readable from the panel — see [Reading logs](https://www.corepanel.net/docs/server-logs).

## Managing the service

```bash
systemctl status corehttpd            # is it up
systemctl reload corehttpd            # re-read site records, no downtime
systemctl restart corehttpd           # drops connections; needed after an .ini change
journalctl -u corehttpd -n 50 --no-pager
rpm -q corepanel-httpd                # the installed version
```

Reload is the normal operation and CorePanel performs it for you on every change; a
restart is only for a change to `/etc/corehttpd.ini`.

> **There is no `corehttpd --version`**
>
> Running `/usr/bin/corehttpd` by hand starts a second server, which fails on the ports the
> running one already holds. Ask the package manager instead: `rpm -q corepanel-httpd`.
## `/etc/corehttpd.ini`

This file is server-wide, and CorePanel manages what matters through the panel — a
per-site setting is never in here. It ships with sensible defaults, it is commented, and
most servers never need it touched. The keys worth knowing about:

| Key | Default | What it does |
|---|---|---|
| `EnableIPAccess` | `true` | Keeps `https://<server-ip>` serving the panel with a self-signed certificate. This is the way back in when DNS breaks or the hostname's certificate expires; set it to `false` to serve the panel by hostname only |
| `MaxPostSizeMB` | `64` | Ceiling on request body size, above any PHP limit |
| `ProxyTimeout` | `60` | Seconds a [proxied route](https://www.corepanel.net/docs/reverse-proxy) may take to respond |
| `WafEventsRetentionDays` | `30` | How long WAF events are kept for the security screens; `0` stops recording them |
| `EnableDynamicCache` | `true` | Box-wide gate for the [page cache](https://www.corepanel.net/docs/web/optimizations); `false` disables it whatever the sites say |

**A change here needs `systemctl restart corehttpd`.** The configuration is read at
start-up only — a reload re-reads the site records, not this file, so an edit followed by
a reload leaves the server running with the old value and no error anywhere.

## When something does not work

Work from the outside in:

1. **Is the server up and were the ports left open?**
   `systemctl status corehttpd` and `ss -lntup | grep corehttpd`. The installer opens 80
   and 443; an empty result means something closed them afterwards — or that a cloud
   provider's own firewall is in front, which CorePanel cannot see.
2. **What did the server answer?** The domain's access log gives the status code, the
   path and the client. `/var/log/corehttpd/error.log` gives the reason.
3. **A 404 on a path the application owns** is almost always the [serving
   mode](https://www.corepanel.net/docs/web/serving-modes), not the server.
4. **A rule that used to work on Apache** — check the per-site `.htaccess`
   [report](https://www.corepanel.net/docs/web/htaccess), which lists every directive that was not applied.
5. **Certificate problems** have their own path: see
   [SSL/TLS certificates](https://www.corepanel.net/docs/ssl-certificates).
