# Server Log Setup



[Server Log Monitoring](/server-logs/introduction) doesn't use a script on your pages. It reads the access logs your server or CDN already writes. This page covers what to prepare before you [connect a log source](/server-logs/connecting-a-source).

## Pick your path [#pick-your-path]

| Your setup                                                     | Use                                                          | Collects                           | Plans      |
| -------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------- | ---------- |
| Site runs through Cloudflare                                   | **Cloudflare Worker**                                        | In real time                       | All plans  |
| Own server (Nginx, Apache, IIS)                                | **SFTP** or **FTPS**                                         | Every 12 to 24 hours, with history | Paid plans |
| Logs shipped to a bucket (AWS ALB, CloudFront, a log pipeline) | **Amazon S3**, **Cloudflare R2** or **Google Cloud Storage** | Every 12 to 24 hours, with history | Paid plans |
| Just want to try it on a file                                  | **Manual upload**                                            | Once per uploaded file             | Paid plans |

## Cloudflare Worker checklist [#cloudflare-worker-checklist]

* [ ] Your domain is a zone on your Cloudflare account, and traffic is proxied through Cloudflare.
* [ ] You can create an API token with **Account → Workers Scripts: Edit**, **Zone → Workers Routes: Edit** and **Zone → Zone: Read**.
* [ ] You accept the Worker cost on your Cloudflare bill (roughly $0.30 per million requests). On Workers Free, collection pauses for the rest of a day once Cloudflare's daily request cap is crossed.
* [ ] Your account has room for one more Worker.

Then follow [Cloudflare Worker](/server-logs/connecting-a-source#cloudflare-worker). Nothing to install on your server.

## Log-file sources [#log-file-sources]

### Where your access logs usually are [#where-your-access-logs-usually-are]

| Server | Typical location                                                                           |
| ------ | ------------------------------------------------------------------------------------------ |
| Nginx  | `/var/log/nginx/access.log` (rotated as `access.log.1`, `access.log.2.gz`, ...)            |
| Apache | `/var/log/apache2/access.log` (Debian/Ubuntu) or `/var/log/httpd/access_log` (RHEL/CentOS) |
| IIS    | `%SystemDrive%\inetpub\logs\LogFiles\W3SVC<site id>\`                                      |

Managed hosts and CDNs often offer a log download or a log export to a bucket instead. Check your host's documentation.

Use a **File path pattern** with a wildcard so rotated files are picked up, for example `/var/log/nginx/access.log*`. Compressed files (`.gz`, `.bz2`, `.zst`, `.zip`) are fine.

### Formats that work [#formats-that-work]

The format is detected automatically. Supported: Combined (Apache/Nginx), custom Nginx `log_format`, IIS (W3C extended), newline-delimited JSON, Cloudflare log fields, AWS Application Load Balancer and AWS CloudFront.

<Callout type="warn">
  Your logs must include the **User-Agent**, because that is how each hit is matched to a bot. The Common Log Format (Apache `common`, without referrer and User-Agent) is rejected. Switch to Combined.
</Callout>

### Fields that unlock more reports [#fields-that-unlock-more-reports]

The more each log line records, the more reports can use it. A source's **Capabilities** line in Settings tells you what it can't capture.

| Field          | Needed for                                                   |
| -------------- | ------------------------------------------------------------ |
| Client IP      | Bot verification, the Security report, fake bot detection    |
| User-Agent     | Identifying the bot at all                                   |
| Status code    | Responses, crawl waste, URLs to fix                          |
| Query string   | Parameter waste in Crawl budget                              |
| Response bytes | Bytes-served figures                                         |
| Response time  | Response time figures and the Googlebot crawl capacity chart |
| Content type   | Crawl budget's content-type breakdown                        |

The default Combined format has no response time. On Nginx, you can add it with a custom `log_format`, for example:

```nginx
log_format vitalsentinel '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         '"$http_referer" "$http_user_agent" '
                         '$request_time "$sent_http_content_type"';

access_log /var/log/nginx/access.log vitalsentinel;
```

If VitalSentinel can't detect a custom format during the connection test, it asks for your **Nginx log\_format directive**. Paste the `log_format` line from your config exactly.

<Callout type="info">
  If your server sits behind a load balancer or CDN, make sure the logged IP is the real client IP (for example via the `X-Forwarded-For` header or your server's real-IP module). Otherwise every hit appears to come from your proxy and bots can't be verified.
</Callout>

### Giving VitalSentinel read access [#giving-vitalsentinel-read-access]

Create a dedicated, **read-only** account for VitalSentinel:

* **SFTP / FTPS:** a user that can read the log directory and nothing else. SFTP can authenticate with a password or a private key (PEM).
* **Amazon S3 / Cloudflare R2 / Google Cloud Storage:** an access key limited to listing and reading the log bucket (or prefix). R2 and GCS need their S3-compatible **Endpoint**.

Credentials are stored encrypted, and they are never sent to a new destination: if you later change the host, port, endpoint or username, you must enter them again.

### Then connect [#then-connect]

Follow [Log-file sources](/server-logs/connecting-a-source#log-file-sources): choose the source type, fill in the connection, click **Test connection**, then **Save**.

## Next steps [#next-steps]

<Cards>
  <Card title="Connecting a Source" href="/server-logs/connecting-a-source">
    The full connect flow for each source
  </Card>

  <Card title="Server Log Monitoring" href="/server-logs/introduction">
    What the module reports
  </Card>
</Cards>
