# HTTP Server Configuration

EMQX Edge includes a built-in HTTP server that serves both the Dashboard web interface and the HTTP API. The following configuration controls how the server is exposed and secured, including the port, connection limit, authentication type, and optional TLS settings for HTTPS access.

## Example Configuration

The following example configures the Dashboard to listen on port `8081`, accept up to 32 concurrent connections, and require basic authentication. The default admin account is defined by `username` and `password`. Additional accounts are stored in the `usernames` and `passwords` arrays. For details, see [Dashboard User Management](../advanced-settings/users.md).

```hocon
http_server {
  port = 8081
  ip_addr = "0.0.0.0"
  limit_conn = 32
  username = "admin"
  password = "<encrypted-password>"
  auth_type = basic
  usernames = ["user1"]
  passwords = ["<encrypted-password>"]
  max_body = 65535
  ssl = {
    enable = false
  }
}
```

## Configuration Items

| Parameter | Type | Default | Description |
|---|---|---|---|
| `port` | Integer | `8081` | Port on which the HTTP server listens. Value range: 0 ~ 65535. |
| `ip_addr` | String | `"0.0.0.0"` | IP address on which the HTTP server listens. |
| `limit_conn` | Integer | `32` | Maximum number of concurrent requests the server can handle. |
| `auth_type` | Enum | `"basic"` | Authentication type for the HTTP server. Values: `"basic"`, `"jwt"`. |
| `username` | String | `"admin"` | Username for the default Dashboard login account. |
| `password` | String | — | Encrypted password for the default Dashboard login account. |
| `usernames` | Array | — | Usernames for additional Dashboard accounts. Each entry corresponds to the encrypted password at the same index in `passwords`. Managed via the Dashboard UI. |
| `passwords` | Array | — | Encrypted passwords for additional Dashboard accounts. Each entry corresponds to the username at the same index in `usernames`. Managed via the Dashboard UI. |
| `max_body` | Integer | `65535` | Maximum HTTP request body size (bytes). |
| `jwt.public.keyfile` | String | — | Path to the public key file for JWT verification. Required when `auth_type` is `"jwt"`. |

## Enable HTTPS for the Dashboard

By default, the Dashboard is served over HTTP. If the Dashboard is accessible over an untrusted network, enabling HTTPS encrypts the connection and prevents credentials from being transmitted in plain text. To enable HTTPS, set `ssl.enable = true` and provide a valid certificate and key.

:::tip Note
HTTPS for the Dashboard is only supported in self-hosted deployments. You must provide your own certificate and key files.
:::

### SSL Configuration Items

| Parameter | Type | Default | Description |
|---|---|---|---|
| `ssl.enable` | Boolean | `false` | Enables HTTPS for the Dashboard. When `true`, the Dashboard is accessible via `https://`. |
| `ssl.key_password` | String | — | Password for the private key file, if the key is password-protected. |
| `ssl.keyfile` | String | — | Path to the server private key file. |
| `ssl.certfile` | String | — | Path to the server certificate file. |
| `ssl.cacertfile` | String | — | Path to the CA certificate or CA bundle used to verify the peer/client certificate when `ssl.verify_peer` is `true`. |
| `ssl.verify_peer` | Boolean | `false` | Whether to require and verify a client certificate. |
| `ssl.fail_if_no_peer_cert` | Boolean | `false` | Whether to reject connections from clients that do not present a certificate. Only takes effect when `ssl.verify_peer` is `true`. |

### Prepare a Self-Signed Certificate

The following example generates a self-signed certificate for testing. Use a CA-issued certificate in production.

1. Create a `san.cnf` file:

   ```ini
   [req]
   default_bits       = 2048
   prompt             = no
   distinguished_name = dn
   req_extensions     = req_ext
   x509_extensions    = v3_ca
   [dn]
   CN = server
   [req_ext]
   subjectAltName = @alt_names
   [v3_ca]
   subjectAltName = @alt_names
   basicConstraints = CA:FALSE
   keyUsage = digitalSignature, keyEncipherment
   extendedKeyUsage = serverAuth
   [alt_names]
   DNS.1 = server
   ```

   The `CN` and `DNS.1` values define the hostname (`server`) that the certificate is valid for. This hostname is used in subsequent steps.

2. Generate the certificate and key:

   ```bash
   openssl req -x509 -nodes -days 825 \
     -newkey rsa:2048 \
     -keyout server.key \
     -out server.crt \
     -config san.cnf
   ```

3. Place `server.key` and `server.crt` in a directory accessible to EMQX Edge, then update `nanomq.conf`:

   ```hocon
   http_server {
     port = 8081
     ip_addr = "0.0.0.0"
     limit_conn = 32
     auth_type = basic
     ssl = {
       enable = true
       keyfile = "/etc/certs/https/server.key"
       certfile = "/etc/certs/https/server.crt"
       cacertfile = "/etc/certs/https/server.crt"
       verify_peer = false
       fail_if_no_peer_cert = false
     }
   }
   ```

4. Add the certificate to the trusted certificate store on the machine running the browser.

   - **macOS:**

     ```bash
     sudo security add-trusted-cert -d -r trustRoot \
       -k /Library/Keychains/System.keychain ./server.crt
     ```

   - **Ubuntu/Debian:**

     ```bash
     sudo cp ./server.crt /usr/local/share/ca-certificates/
     sudo update-ca-certificates
     ```

   On other operating systems, refer to your system documentation for adding a trusted root certificate.

5. Add the server hostname to `/etc/hosts` on the machine running the browser, replacing `<ip-address>` with the actual IP address of the EMQX Edge host:

   ```text
   <ip-address> server
   ```

6. Restart EMQX Edge, reopen the browser, then open `https://server:8081/`.

### Verify the HTTPS Configuration

To confirm that the Dashboard is being served over HTTPS correctly, run the following command. It checks that the server completes the TLS handshake and negotiates the `http/1.1` application protocol via ALPN.

```bash
curl -v --cacert server.crt https://server:8081 2>&1 | grep -i alpn
```

The output should include:

```text
ALPN: server accepted http/1.1
```
