> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# appsettings.json

`appsettings.json` is the core configuration file of GZCTF, which is configured by mounting into the container. This document will introduce the meaning of each field in the configuration file.

:::info

You need to restart the GZCTF service every time you update `appsettings.json` to make it effective.

:::

## Structure of the configuration file

Here is a complete example of configuration:

```json
{
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Database": "Host=db:5432;Database=gzctf;Username=postgres;Password=<Database Password>"
    // redis is optional
    // "RedisCache": "cache:6379,password=<Redis Password>",
    // local disk storage (default) or s3-compatible storage (optional)
    // "Storage": "disk://path=./files" or "s3://accessKey=<YOUR_ACCESS_KEY>;secretKey=<YOUR_SECRET_KEY>;bucket=<YOUR_BUCKET>;region=<YOUR_REGION>"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Loki": {
      "Enable": true,
      "EndpointUri": "http://loki:3100",
      "Labels": [
        {
          "Key": "app",
          "Value": "gzctf"
        }
      ],
      "PropertiesAsLabels": ["app"],
      "Credentials": {
        "Login": "login",
        "Password": "password"
      },
      "Tenant": "my-tenant",
      "MinimumLevel": "Trace"
    }
  },
  "Telemetry": {
    "Prometheus": {
      "Enable": false,
      "TotalNameSuffixForCounters": false
    },
    "OpenTelemetry": {
      "Enable": false,
      "Protocol": "Grpc",
      "EndpointUri": "http://jaeger-collector:4317"
    },
    "AzureMonitor": {
      "Enable": false,
      "ConnectionString": "InstrumentationKey=12345678-abcd-abcd-abcd-12345678..."
    },
    "Console": {
      "Enable": false
    }
  },
  "EmailConfig": {
    "SenderAddress": "",
    "SenderName": "",
    "UserName": "",
    "Password": "",
    "Smtp": {
      "Host": "localhost",
      "Port": 587,
      "BypassCertVerify": false
    }
  },
  "XorKey": "<Random Key Str>",
  "ContainerProvider": {
    "Type": "Docker", // or "Kubernetes"
    "PortMappingType": "Default",
    "EnableTrafficCapture": false,
    "PublicEntry": "ctf.example.com", // or "xxx.xxx.xxx.xxx"
    "DockerConfig": {
      // optional
      "ChallengeNetwork": "",
      "Uri": "unix:///var/run/docker.sock",
      "UserName": "",
      "Password": ""
    },
    "KubernetesConfig": {
      // optional
      "Namespace": "gzctf-challenges",
      "ConfigPath": "kube-config.yaml",
      "AllowCIDR": [
        // allow the cluster CIDR for LB
        "10.0.0.0/8"
      ],
      "DNS": [
        // custom DNS to avoid cluster DNS
        "8.8.8.8",
        "223.5.5.5"
      ]
    }
  },
  "RequestLogging": false,
  "DisableRateLimit": false,
  "Registries": {
    "ghcr.io": {
      "UserName": "...",
      "Password": "ghp_..."
    }
  },
  "CaptchaConfig": {
    "Provider": "None",
    "SiteKey": "...",
    "SecretKey": "...",
    // optional
    "HashPow": {
      "Difficulty": 18
    }
  },
  "ForwardedOptions": {
    "ForwardedHeaders": 7, // a flag enum, see following link
    "ForwardLimit": 1,
    "ForwardedForHeaderName": "X-Forwarded-For",
    // use the following options to allow proxy
    "KnownIPNetworks": ["10.0.0.0/8"],
    "KnownProxies": ["10.0.0.1"]
  },
  "Kestrel": {
    "Limits": {
      "MaxResponseBufferSize": 2048,
      "MaxRequestBufferSize": 1048576,
      "MaxRequestLineSize": 8192,
      "MaxRequestHeadersTotalSize": 32768,
      "MaxRequestHeaderCount": 100,
      "MaxRequestBodySize": 27262946,
      "KeepAliveTimeout": "0.0:5:0",
      "RequestHeadersTimeout": "0.0:5:0",
      "MaxConcurrentConnections": null,
      "MaxConcurrentUpgradedConnections": null
    },
    "AddServerHeader": true,
    "AllowResponseHeaderCompression": true,
    "AllowSynchronousIO": false,
    "AllowAlternateSchemes": false,
    "DisableStringReuse": false,
    "ConfigurationLoader": null
  }
}
```

## Configuration fields

### ConnectionStrings

Here we can configure the connection of the database.

#### `Database`

This field is required.

GZCTF uses PostgreSQL as the backend database and data persistence.

:::info

GZCTF only supports PostgreSQL as the database, and does not support MySQL and other databases. Please fill in the correct database connection settings in the configuration file.

:::

#### `RedisCache`

This field is optional.

GZCTF uses Redis as the cache and message queue. In the case of single instance deployment, Redis is not necessary, and GZCTF's memory cache can be used directly; in the case of multi-instance deployment, Redis is necessary as a shared cache and SignalR's Scale-Out broadcast.

In v1.0 and later, GZCTF supports using [Garnet](https://github.com/microsoft/garnet) as the cache service.

#### `Storage`

This field is optional.

GZCTF supports two types of storage providers:

- **Local Disk Storage (default)**

  `disk://path=./files`

  - `path`: Optional. Path to store files locally (default: `./files`)

- **S3-compatible Storage** (AWS S3, MinIO, DigitalOcean Spaces, etc.)

  `s3://accessKey=...;secretKey=...;bucket=...;region=...`

  or use the following scheme for convenience:

  - `aws.s3://...` (equivalent to `s3://...`)

  Parameters:

  - `accessKey`: Optional. Access Key ID
  - `secretKey`: Optional. Secret Access Key
  - `bucket`: Bucket name
  - `region`: Region (such as `us-east-1`)
  - `endpoint`: Optional. Custom endpoint URL (for MinIO or other S3-compatible services)
  - `useHttp`: Optional. Whether to use HTTP instead of HTTPS (default: false)
  - `forcePathStyle`: Optional. Whether to use path-style URLs instead of virtual-hosted-style (default: false). **Must be `true` when a custom `endpoint` is used** (MinIO/RustFS or other S3-compatible services), otherwise requests use virtual-hosted-style (`<bucket>.<endpoint-host>`) and fail.

For more information, see the following links:

- [AWS S3](https://docs.aws.amazon.com/s3/index.html)
- [MinIO S3](https://docs.min.io/)

### Logging

You can configure the logging level and scopes. In addition, GZCTF also supports sending logs to Loki server.

- **LogLevel**: The minimal logging level per namespace.
- **Loki**: The configuration of Loki server.
  - **Enable**: Enable it or not.
  - **EndpointUri**: The URI of Loki server.
  - **Labels**: Optional. The global log event labels.
  - **PropertiesAsLabels**: Optional. The list of properties, which should be mapped to Loki labels.
  - **Credentials**: Optional. Credentials, which will be used for basic auth
  - **Tenant**: Optional. The Tenant ID used for sending logs to Loki server.
  - **MinimumLevel**: Optional. Minimal logging level.

Available logging levels: Trace, Debug, Information, Warning, Error, Critical, None.

### Telemetry

GZCTF supports metrics and distributed tracing. You can configure the providers you want to use.

- **Prometheus**: Prometheus endpoint support.
  - **Enable**: Enable it or not.
  - **TotalNameSuffixForCounters**: Optional. Whether to include `_total` suffix in counters or not.

- **OpenTelemetry**: Exporting metrics and tracing data to OpenTelemetry.
  - **Enable**: Enable it or not.
  - **Protocol**: `Grpc` or `HttpProtobuf`.
  - **EndpointUri**: The OpenTelemetry endpoint URI to push telemetry data.

- **AzureMonitor**: Exporting metrics and tracing data to ApplicationInsights.
  - **Enable**: Enable it or not.
  - **ConnectionString**: The connection string.

- **Console**: Exporting tracing data to console.
  - **Enable**: Enable it or not.

### EmailConfig

Here we can configure the information of email sending server. If you use email registration and other email features, this is required.

- **SenderAddress:** Email address of the sender
- **SenderName:** Name of the sender
- **UserName:** SMTP Server username
- **Password:** SMTP Server password
- **Smtp:** SMTP Server address and port
- **BypassCertVerify:** Whether to bypass the certificate verification of the SMTP server

:::info

Some cloud service providers may block port 465, please try port 587.

:::

### XorKey

Configure the encryption key used to encrypt the competition private keys stored in the database. It can be any string of any length.

### ContainerProvider

Configure the container backend, which is required for creating containers dynamically during the game.

- **Type:** Type of the container backend. Can be `Docker` or `Kubernetes`.
- **PublicEntry:** Public entry of the container backend, used to generate the competition access address that is shown to participating teams.
- **PortMappingType:** Port mapping type. Can be `Default` or `PlatformProxy`.
- **EnableTrafficCapture:** Enable or disable traffic capture. Only available when `PortMappingType` is set to `PlatformProxy`. Captured traffic is saved to `/app/files/capture`.

#### Docker

:::warning

Docker Swarm is no longer supported since v1.8.0. Please use Kubernetes for better security and scalability.

:::

- **Uri:** Docker API Server Address
  - If you use local Docker, leave `Uri` empty and mount `/var/run/docker.sock` into the container.
  - If you use external Docker, set `Uri` to the corresponding Docker API server. **External API authentication is recommended.**

- **ChallengeNetwork:**

  **Before v1.8.0**

  Specify the network where the challenge container is located. If not specified, the default Docker network is used.

  **After v1.8.0**

  Treat this value as the **network prefix** for creating challenge networks. GZCTF automatically creates two networks for different network modes: `<ChallengeNetwork>-open` for open network mode and `<ChallengeNetwork>-isolated` for isolated network mode.

  You can also manually create a `<ChallengeNetwork>-custom` network for custom network mode, and configure it according to your needs.

- **UserName, Password:** Docker API Basic Auth username and password, optional.

#### Kubernetes

- **Namespace:** Kubernetes namespace used to create challenge instances. The default value is `gzctf-challenges`.
- **ConfigPath:** Kubernetes configuration file path used to connect to the cluster. The default value is `kube-config.yaml`.
- **AllowCIDR:** CIDR whitelist that is allowed to access Pods.
- **DNS:** Custom DNS server list.

To use the default behavior, put the cluster connection configuration into the `kube-config.yaml` file and mount it to the `/app` directory. Do not change this configuration if you are not familiar with the behavior of the experimental features.

:::info

Make sure to change the `server` field in the `kube-config.yaml` file so that it points to the API server address of the cluster. The default address is usually `https://127.0.0.1:6443`, and it must be updated to the actual address of your cluster.

:::

:::info

**Before v1.8.0**

To enforce basic network isolation, GZCTF creates a NetworkPolicy named `gzctf-policy` in the challenge namespace to restrict access. GZCTF automatically detects whether this NetworkPolicy already exists. If it does, it will not be created again, so you can customize the network policy by creating or editing this NetworkPolicy.

**After v1.8.0**

GZCTF creates two NetworkPolicies named `gzctf-network-open` and `gzctf-network-isolated` in the challenge namespace to restrict access for open and isolated network modes respectively. GZCTF automatically maintains these NetworkPolicies, so do not modify or delete them manually.

You can **customize the network policy** by creating additional NetworkPolicies in the same namespace. You can select target Pods by using the following labels:

- `gzctf.gzti.me/TeamId`: Select specific teams
- `gzctf.gzti.me/UserId`: Select specific users
- `gzctf.gzti.me/ChallengeId`: Select specific challenges
- `gzctf.gzti.me/NetworkMode`: Select specific network modes (`open`, `isolated`, `custom`)

:::

### RequestLogging

Enable/Disable request logging, if enabled, detailed information of each request will be appended to the log. Static file requests are not included in the output here.

:::warning

This configuration item will record specific request information, which can **significantly impact** the log file size and platform concurrency performance. Please enable it only during debugging.

:::

### DisableRateLimit

Enable/Disable request rate limit, if enabled, the request rate of each IP and API will be limited according to the preset rules.

:::danger

**This feature is fundamental to the security of GZCTF, take your own risk when disabling it.**

In most cases, there is no situation where users can reach the rate limit. If you encounter frequent triggering of the rate limit and abnormal IP information in the backend logs (such as a large number of requests from the same IP), please check the **trusted proxy configurations**.

With this configuration enabled, GZCTF can use minimal resources to block malicious requests that exceed normal requests by dozens of times, ensuring the platform’s stable operation.

:::

### RegistryConfig

:::warning

**This configuration item is deprecated, please use the `Registries` field instead.**

:::

### Registries

Here we can configure the username and password of the Docker Registry, which is used to pull the container image for dynamic container during the game.

```json
"Registries": {
  "ghcr.io": {
    "UserName": "...",
    "Password": "ghp_..."
  },
  "docker.io": {
    "UserName": "...",
    "Password": "..."
  },
  "your.custom.registry": {
    "UserName": "...",
    "Password": "..."
  }
}
```

You can customize the configuration of other registries according to the above format. The `UserName` and `Password` fields are required.

:::info

Please make sure that the password does not contain special characters (such as `":@` etc., but `_` can be used), otherwise it may cause template injection problems and make `Secret` not work properly.

:::

### CaptchaConfig

Configure the CAPTCHA used for user registration, account recovery and login, optional.

- **Provider:** CAPTCHA provider, can be `None`, `HashPow` or `CloudflareTurnstile`
- **SiteKey:** CAPTCHA Sitekey
- **SecretKey:** CAPTCHA Secretkey

:::tip

To ensure security and avoid malicious registration and email consumption, it is strongly recommended to enable the CAPTCHA function.

It is recommended to use the `CloudflareTurnstile` CAPTCHA provider, [related documentation](https://www.cloudflare.com/application-services/products/turnstile/).

:::

#### HashPow

Configure the HashPow captcha related information, optional.

:::info

**Secure context**: This feature is available only in [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) (HTTPS).

:::

- **Difficulty:** Difficulty of HashPow captcha, used to specify the number of leading zeros in the hash bits. The available range is from 8 to 48.

#### GoogleRecaptcha

:::warning

**Removed in v1.2.2.** The Google ReCaptcha support was removed due to the lack of maintenance of the upstream dependency.

Please use the `CloudflareTurnstile` CAPTCHA provider instead.

:::

### ForwardedOptions

Here we can configure the reverse proxy, which is used to get the real IP address, optional.

- **ForwardedHeaders:** Enum for ForwardedHeaders in reverse proxy, please use `7` as the default value. For more details, see [ForwardedHeaders Enum](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.httpoverrides.forwardedheaders)
- **ForwardLimit:** Limit the number of proxy hops allowed, the default is `1`
- **ForwardedForHeaderName:** The name of the reverse proxy IP address header
- **KnownIPNetworks:** List of trusted networks for reverse proxy, represented by CIDR.
- **KnownProxies:** List of trusted proxies for reverse proxy, represented by IP addresses or domain names.

:::info

If you want to ignore the trust list of reverse proxies and allow any IP address to access, please refer to the solution for forwarding Linux and non-IIS reverse proxies, and set the environment variable `ASPNETCORE_FORWARDEDHEADERS_ENABLED` to `true`.

:::

For other fields, please refer to the official documentation: [Configure ASP.NET Core to work with proxy servers and load balancers](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer) and [ForwardedHeadersOptions class](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.forwardedheadersoptions)

### Kestrel

:::warning In most cases, you don't need to modify the Kestrel configuration.

Kestrel is the built-in web server used by GZCTF.

With this configuration, you can control the behavior of Kestrel, such as specifying the HTTP protocol, modifying the request size limit, and more.

For other configurable fields, please refer to the properties of the `KestrelServerOptions` class in the official documentation: [KestrelServerOptions class](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.server.kestrel.core.kestrelserveroptions)

:::
