> ## Documentation Index
> Fetch the complete documentation index at: https://verifyngo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# verifyngo quickstart: Docker setup and config guide

> Run verifyngo as a reverse-proxy bot filter in front of your web service using Docker and a config.json file. No changes to your app are required.

This page walks you through getting verifyngo running in front of your web service in a few minutes. You will create a single `config.json` file, start a Docker container, and point your existing reverse proxy at it — no changes to your app required.

<Steps>
  <Step title="Create your config file">
    Create a `config.json` file in your working directory. The example below covers the essential fields to get up and running.

    ```json config.json theme={null}
    {
      "listen_addr": "0.0.0.0:8080",
      "upstream_url": "http://your-app:3000",
      "cookie_secret": "replace-with-32-byte-hex-secret",
      "provider": "turnstile",
      "turnstile": {
        "site_key": "your-turnstile-site-key",
        "secret_key": "your-turnstile-secret-key"
      },
      "default_action": "challenge"
    }
    ```

    <Note>
      * **`upstream_url`** — the address of your actual application. verifyngo forwards every verified request here.
      * **`cookie_secret`** — a random 32-byte hex string used to sign session cookies. Generate one with `openssl rand -hex 32` and never reuse it across deployments.
      * **`provider`** — selects which CAPTCHA provider verifyngo presents to visitors. Supported values are `turnstile`, `hcaptcha`, and `cap`.
    </Note>
  </Step>

  <Step title="Run with Docker">
    Start verifyngo as a container, mounting your config file as read-only.

    <CodeGroup>
      ```bash docker run theme={null}
      docker run -d \
        -p 8080:8080 \
        -v $(pwd)/config.json:/config.json:ro \
        ghcr.io/chocolatemoo53/verifyngo:latest
      ```

      ```yaml docker compose theme={null}
      services:
        verifyngo:
          image: ghcr.io/chocolatemoo53/verifyngo:latest
          ports:
            - "8080:8080"
          volumes:
            - ./config.json:/config.json:ro
            - verifyngo-data:/data
          environment:
            - TZ=UTC
          restart: unless-stopped

      volumes:
        verifyngo-data:
      ```
    </CodeGroup>

    verifyngo is now listening on port `8080` and will proxy verified traffic to the `upstream_url` you configured.
  </Step>

  <Step title="Point your reverse proxy at verifyngo">
    Update your Nginx, Caddy, or Traefik configuration to send incoming traffic to `localhost:8080` — where verifyngo is listening — instead of directly to your app. verifyngo handles the challenge flow and forwards only verified requests upstream. Your application code does not need to change.

    Here is a minimal Nginx example:

    ```nginx theme={null}
    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://localhost:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
    ```

    <Tip>
      When you have a reverse proxy in front of verifyngo, enable `"trust_real_ip": true` in your `config.json` and add the proxy's IP address to `"trusted_proxies"`. This ensures verifyngo evaluates the real visitor IP rather than the proxy's address.

      ```json theme={null}
      "trust_real_ip": true,
      "trusted_proxies": ["127.0.0.1"]
      ```
    </Tip>
  </Step>

  <Step title="Test it">
    Open your site in a browser. Because `default_action` is set to `challenge`, you will see the CAPTCHA page on your first visit. Solve it once and verifyngo sets a signed cookie — you won't be challenged again until that cookie expires (the default is 7 days, controlled by `cookie_ttl`).

    To confirm everything is working, open a private browsing window and visit your site again. You should see the challenge page. After solving it, subsequent requests in the same browser session should pass straight through to your app.

    <Note>
      By default, verifyngo keeps ban and walkaway state in memory, which means that state is lost when the container restarts. For production deployments, set `store.backend` to `"file"` or `"redis"` in your `config.json` so that state persists across restarts. See [Persistence](/configuration/persistence) for full details.
    </Note>
  </Step>
</Steps>
