HTTP Server

The HTTP Server sample demonstrates how to host an HTTP server on a Nordic Semiconductor device that is connected to the Internet through LTE or Wi-Fi®.

Cellular connectivity is supported on the nRF91 Series SiPs, while Wi-Fi connectivity is supported on the nRF52 or nRF53 Series SoCs hosting the nRF70 Series Wi-Fi companion ICs.

The sample uses the connection manager that provides a common connectivity API for LTE and Wi-Fi stacks.

Requirements

The sample supports the following development kits:

Hardware platforms

PCA

Board name

Build target

Thingy:91

PCA20035

thingy91_nrf9160

thingy91_nrf9160_ns

nRF9161 DK

PCA10153

nrf9161dk_nrf9161

nrf9161dk_nrf9161_ns

nRF9160 DK

PCA10090

nrf9160dk_nrf9160

nrf9160dk_nrf9160_ns

nRF9151 DK

PCA10171

nrf9151dk_nrf9151

nrf9151dk_nrf9151_ns

nRF7002 DK

PCA10143

nrf7002dk_nrf5340

nrf7002dk_nrf5340_cpuapp_ns

When built for an _ns build target, the sample is configured to compile and run as a non-secure application with Cortex-M Security Extensions enabled. Therefore, it automatically includes Trusted Firmware-M that prepares the required peripherals and secure services to be available for the application.

Overview

The sample supports managing the state of LED 1 and LED 2 on a compatible development kit. This feature allows you to both set and retrieve the current state of the LEDs through HTTP calls from a REST client.

Moreover, the sample also offers the option to enable TLS for secure communication. You can configure TLS with or without server and/or device authentication based on your security requirements.

There are slight differences in how the sample behaves depending on the wireless technology for which the sample is built. The following table explains some of these differences:

Network access

LED resource URL

Security

Peer verification

IP family [3]

Wi-Fi

Local

http://httpserver.local/led/<led_id>

TLS (optional)

Server and client [2]

IPv4 IPv6

Cellular

Global [1]

http://<ip>/led/<led_id>

TLS (optional)

Server and client [2]

IPv4 IPv6

When the server is built for Wi-Fi, the server’s availability is limited to the local network. It can also be globally available by configuring your AP and giving it a static IP, but this is not covered in this documentation.

The sample supports mDNS with a hostname set by the CONFIG_NET_HOSTNAME option, which defaults to httpserver.local. To access the server there are a few considerations. Not all access points support IPv6. The access points that support IPv6 is required to enable the appropriate IPv6 settings mentioned in the configuration page of the access points. To check if the device is assigned an IP, run the following shell command in a serial terminal connected to the server:

uart:~$ net ipv6
...
IPv6 addresses for interface 1 (0x200190d0) (WiFi)
================================================
Type            State           Lifetime (sec)  Address
autoconf        preferred       infinite        fe80::f7ce:37ff:fe00:1971/128
autoconf        preferred       9250            2001:8c0:5140:895:f7ce:37ff:fe00:1971/64

If the device has received a valid IPv6 address, it is usually assigned a lifetime and has an address slightly longer than its local IPv6 address, a combination of a local and global address. In this case, the address is 2001:8c0:5140:895:f7ce:37ff:fe00:1971.

Security

To prevent attackers from getting access to the server, the sample supports TLS with the option of enabling peer verification. With peer verification, the server requires that the client is authenticated during the TLS handshake process. This requires that the client include a client certificate in the REST call that will be used to prove its authenticity.

To enable TLS, the sample includes pregenerated credentials that are located in the sample folder:

  • http_server/credentials/server_certificate - Self-signed server certificate

  • http_server/credentials/server_private_key - Server certificate private key

  • http_server/credentials/client.crt - Client certificate

  • http_server/credentials/client.key - Client private key

Note

These should only be used for testing purposes.

Peer verification can be used by building the sample with the CONFIG_HTTP_SERVER_SAMPLE_PEER_VERIFICATION_REQUIRE Kconfig option, and passing the appropriate credentials when making the HTTP calls. These pregenerated credentials work only when you are building for Wi-Fi and running the server on your local Wi-Fi network. You need to generate new credentials when building for cellular due to a CN mismatch. To generate new credentials, run the following commands:

# Generate a new RSA key pair (private key and public key) and create a self-signed X.509 certificate for a server.
openssl req -newkey rsa:2048 -nodes -keyout server_private_key.pem -x509 -days 365 -out server_certificate.pem

# Generate a new RSA private key for a client.
openssl genpkey -algorithm RSA -out client.key

# Create a Certificate Signing Request (CSR) for the client using the generated private key.
openssl req -new -key client.key -out client.csr

# Sign the client's CSR with the server's private key and certificate, creating a client certificate.
openssl x509 -req -in client.csr -CA server_certificate.pem -CAkey server_private_key.pem -CAcreateserial -out client.crt -days 365

To provision the generated credentials to the server’s TLS stack, replace the pregenerated certificates with the newly generated one in the http_server/credentials folder in PEM format. Provisioning happens automatically after the firmware boots by the sample.

Configuration

See Configuring and building an application for information about how to permanently or temporarily change the configuration.

Configuration options

The following lists the application-specific configurations used in the sample. They are located in the samples/net/http_server/Kconfig file.

CONFIG_HTTP_SERVER_SAMPLE_PEER_VERIFICATION_REQUIRE

This configuration option enables peer verification for the sample. Enabling peer verification ensures that the server validates the authenticity of the client during the TLS handshake.

CONFIG_HTTP_SERVER_SAMPLE_PORT

This configuration option sets the server port for the sample.

CONFIG_HTTP_SERVER_SAMPLE_CLIENTS_MAX

This configuration option sets the maximum number of concurrent clients for the sample. Increasing this option impacts the server’s performance and increases the total memory footprint, as each client instance has its own thread with a dedicated stack. The option sets the number of maximum concurrent clients per IP family, allowing a total of 4 clients to be connected simultaneously if both IPv4 and IPv6 are enabled and the value is set to 2.

CONFIG_HTTP_SERVER_SAMPLE_SERVER_CERTIFICATE_SEC_TAG

This configuration option sets the security tag for the credentials used in TLS.

CONFIG_HTTP_SERVER_SAMPLE_STACK_SIZE

This configuration option sets the stack size for the threads used in the sample.

CONFIG_HTTP_SERVER_SAMPLE_RECEIVE_BUFFER_SIZE

This configuration option sets the receive buffer size for the sockets used in the sample.

Configuring Wi-Fi access point credentials

This sample uses the Wi-Fi credentials library to manage Wi-Fi credentials. Before the sample can connect to a Wi-Fi network, you must configure at least one credential set.

Once you have flashed your device with this sample, connect to your device’s UART interface and add credentials using the following command:

wifi_cred add NetworkSSID SecurityMode (OPEN, WPA2-PSK, WPA2-PSK-SHA256, WPA3-SAE) NetworkPassword

Where NetworkSSID is replaced with the SSID of the Wi-Fi access point you want your device to connect to, and NetworkPassword is its password. If you are not sure which security mode to use, enable the CONFIG_NET_L2_WIFI_SHELL Kconfig option and use the wifi scan command to display a list of all accessible networks along with their corresponding security modes. Then either reboot the device or use the wifi_cred auto_connect command to manually trigger a connection attempt.

From now on, these credentials will be automatically used when the configured network is reachable.

When building as firmware image for a non-secure build target, the Wi-Fi credentials backend will be set to PSA using TF-M.

See the Wi-Fi: Shell sample document for more details on the wifi_cred command.

Wi-Fi static credential options

If you want to configure the credentials statically, set the CONFIG_WIFI_CREDENTIALS_STATIC Kconfig option to y.

Important

Do not use static credentials in production environments.

Other options for statically configuring your Wi-Fi credentials:

Configuration files

The sample includes pre-configured configuration files for the development kits that are supported:

  • prj.conf - For all devices.

  • boards/nrf7002dk_nrf5340_cpuapp_ns.conf - For the nRF7002 DK.

  • boards/nrf9151dk_nrf9151_ns.conf - For the nRF9151 DK.

  • boards/nrf9161dk_nrf9161_ns.conf - For the nRF9161 DK.

  • boards/nrf9160dk_nrf9160_ns.conf - For the nRF9160 DK.

  • boards/thingy91_nrf9160_ns.conf - For the Thingy:91.

Files that are located under the /boards folder are automatically merged with the prj.conf file when you build for the corresponding target.

Building and running

This sample can be found under samples/net/http_server in the nRF Connect SDK folder structure.

When built as firmware image for the _ns build target, the sample has Cortex-M Security Extensions (CMSE) enabled and separates the firmware between Non-Secure Processing Environment (NSPE) and Secure Processing Environment (SPE). Because of this, it automatically includes the Trusted Firmware-M (TF-M). To read more about CMSE, see Processing environments.

To build the sample with Visual Studio Code, follow the steps listed on the How to build an application page in the nRF Connect for VS Code extension documentation. See Configuring and building an application for other building scenarios, Programming an application for programming steps, and Testing and optimization for general information about testing and debugging in the nRF Connect SDK.

Testing

After programming the sample to your development kit, complete the following steps to test it:

  1. Connect the kit to the computer using a USB cable. The kit is assigned a COM port (Windows) or ttyACM device (Linux), which is visible in the Device Manager.

  2. Connect to the kit with a terminal emulator (for example, nRF Connect Serial Terminal). See Testing and optimization for the required settings and steps.

  3. Reset your board.

  4. Observe that the board connects to the network and waits for incoming HTTP connections.

  5. Set or get the value of the two supported LEDs by performing REST calls to either of the two resource URLs. In the following example, HTTPie is used:

Non TLS (unsecure):

http PUT http://httpserver.local:80/led/1 --raw="1"
http GET http://httpserver.local:80/led/1

TLS with server authentication:

https PUT https://httpserver.local:443/led/1 --raw="1" --verify server_certificate.pem
https GET https://httpserver.local:443/led/1 --verify server_certificate.pem

TLS with server authentication and client authentication:

https PUT https://httpserver.local:443/led/1 --raw="1" --verify server_certificate.pem --cert client.crt --cert-key client.key
https GET https://httpserver.local:443/led/1 --verify server_certificate.pem --cert client.crt --cert-key client.key

It might be required to specify the IP address directly in the REST command if it does not work using the hostname:

http PUT 'http://[2001:8c0:5140:895:f7ce:37ff:fe00:1971]:81/led/1' --raw="1"

Sample output

The following serial UART output is displayed in the terminal emulator when running the sample:

*** Booting nRF Connect SDK v3.4.99-ncs1-4667-g883c3709f9c8 ***
[00:00:00.529,632] <inf> http_server: HTTP Server sample started
[00:00:00.554,504] <inf> http_server: Network interface brought up
uart:~$ wifi_cred add "cia-asusgold" WPA2-PSK thingy91rocks
uart:~$ wifi_cred auto_connect
[00:00:53.984,100] <inf> http_server: Network connected
[00:00:53.985,778] <inf> http_server: Waiting for IPv6 HTTP connections on port 81, sock 9
[00:00:54.986,511] <inf> http_server: Waiting for IPv4 HTTP connections on port 80, sock 10
[00:01:20.705,139] <inf> http_server: [11] Connection from 192.168.50.134 accepted
[00:01:20.710,998] <inf> http_server: LED 0 state updated to 1
uart:~$

The following serial output is from the terminal window that performs the HTTP calls:

➜  ~ http PUT http://httpserver.local:80/led/1 --raw="1"
HTTP/1.1 200 OK

➜  ~ http GET http://httpserver.local:80/led/1
HTTP/1.1 200 OK
Content-Length: 1

1

Troubleshooting

If you have issues with connectivity on nRF91 Series devices, see the Cellular Monitor documentation to learn how to capture modem traces to debug network traffic in Wireshark. Modem traces can be enabled by providing a snippet with the west build command using the -S argument as shown in the following example for nRF9161 DK:

west build -p -b nrf9161dk_nrf9161_ns -S nrf91-modem-trace-uart

Dependencies

This sample uses the following Zephyr libraries: