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 |
Board target |
---|---|---|---|
PCA20035 |
thingy91 |
|
|
PCA10153 |
|
||
PCA10090 |
|
||
PCA10171 |
|
||
PCA10143 |
|
||
Native Simulator |
native_sim |
|
When built for a board target with the */ns
variant, 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
.
To use a static SIM card, you may need to instruct the modem to use a specific Access Point Name (APN). This can be carried out by setting the following options:
CONFIG_PDN_DEFAULTS_OVERRIDE
- Used to override the default PDP context configuration. Set the option toy
to override the default PDP context configuration.CONFIG_PDN_DEFAULT_APN
- Used for manual configuration of the APN. An example isapn.example.com
.
To verify that you have properly set up the AP and given a static IP, perform the following:
Enable the
CONFIG_AT_HOST_LIBRARY
option.Run the
AT+CGDCONT?
AT command on a serial terminal. The command returns the available Packet Data Network (PDN) context with the accompanied APNs and given IPs. If you reboot the device, you should get the same IP.
You might also want to address the responsiveness of the server. By default, the server disables both Power Saving Mode (PSM) and Extended Discontinuous Reception (eDRX) to ensure maximum availability, which increases the power consumption of the server. So, you can reduce power consumption by putting the device in sleep mode more frequently.
A lot of networks do not cache downlink data when the device sleeps. So, requests can drop if sent when the device is in PSM. For more information on power-saving features and how to use them, see Enabling power-saving features.
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 certificatehttp_server/credentials/server_private_key
- Server certificate private keyhttp_server/credentials/client.crt
- Client certificatehttp_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 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 board 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:
CONFIG_WIFI_CREDENTIALS_STATIC
- This option enables static Wi-Fi configuration.CONFIG_WIFI_CREDENTIALS_STATIC_SSID
- Wi-Fi SSID.CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD
- Wi-Fi password.CONFIG_WIFI_CREDENTIALS_STATIC_TYPE_OPEN
- Wi-Fi network uses no password.CONFIG_WIFI_CREDENTIALS_STATIC_TYPE_PSK
- Wi-Fi network uses a password and PSK security (default).CONFIG_WIFI_CREDENTIALS_STATIC_TYPE_PSK_SHA256
- Wi-Fi network uses a password and PSK-256 security.CONFIG_WIFI_CREDENTIALS_STATIC_TYPE_SAE
- Wi-Fi network uses a password and SAE security.
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 a board target with the */ns
variant, 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, follow the instructions in Building an application for your preferred building environment. See also Programming an application for programming steps and Testing and optimization for general information about testing and debugging in the nRF Connect SDK.
Note
When building repository applications in the SDK repositories, building with sysbuild is enabled by default.
If you work with out-of-tree freestanding applications, you need to manually pass the --sysbuild
parameter to every build command or configure west to always use it.
Testing
After programming the sample to your development kit, complete the following steps to test it:
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.
Connect to the kit with a terminal emulator (for example, nRF Connect Serial Terminal). See Testing and optimization for the required settings and steps.
Reset your board.
Observe that the board connects to the network and waits for incoming HTTP connections.
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"
Non TLS (unsecure):
http PUT http://<ip>:80/led/1 --raw="1"
http GET http://<ip>:80/led/1
TLS with server authentication:
https PUT https://<ip>:443/led/1 --raw="1" --verify server_certificate.pem
https GET https://<ip>:443/led/1 --verify server_certificate.pem
TLS with server authentication and client authentication:
https PUT https://<ip>:443/led/1 --raw="1" --verify server_certificate.pem --cert client.crt --cert-key client.key
https GET https://<ip>:443/led/1 --verify server_certificate.pem --cert client.crt --cert-key client.key
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:~$
[00:00:00.416,839] <inf> http_server: HTTP Server sample started
[00:00:00.687,652] <inf> http_server: Network interface brought up
[00:00:03.047,210] <inf> http_server: Network connected
[00:00:03.048,522] <inf> http_server: Waiting for IPv6 HTTP connections on port 81, sock 0
[00:00:04.057,067] <inf> http_server: Waiting for IPv4 HTTP connections on port 80, sock 1
[00:00:19.522,796] <inf> http_server: [2] Connection from 194.19.86.146 accepted
[00:00:19.557,128] <inf> http_server: LED 0 state updated to 1
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 as shown in the following example for nRF9161 DK:
west build -p -b nrf9161dk/nrf9161/ns -- -Dhttp_server_SNIPPET="nrf91-modem-trace-uart"
Dependencies
This sample uses the following Zephyr libraries:
zephyr/net/http/parser.h