PQCready™ NGINX AMI
Last Updated: January 31, 2026
This guide covers the setup and configuration of the PQCready NGINX AMI, which includes a pre-configured NGINX web server with post-quantum cryptographic capabilities.
Overview
The PQCready NGINX AMI provides a PQCready web server with quantum-resistant TLS support. It includes:
- OpenSSL with OQS Provider - Post-quantum cryptographic algorithms
- NGINX - High-performance web server configured for PQC TLS
- ML-DSA (Dilithium) - NIST-standardized post-quantum digital signature algorithm
Contact Us for PQCready™ NGINX AMI
Certificate Generation
Use the PQCrypto CLI Docker image to generate post-quantum certificates on your local machine.
Step 1: Set Up Docker Environment
Pull the PQCrypto CLI Docker image from Docker Hub:
$ docker pull pqcrypto/pqcrypto-cli:latest
Launch an interactive shell inside the container with a volume mount for outputting generated files:
$ docker run -it -v $(pwd):/output --entrypoint /bin/bash pqcrypto/pqcrypto-cli
Step 2: Generate PQC CA Private Key
Inside the Docker container, generate a Certificate Authority private key using the ML-DSA algorithm:
2.1 - Create private key with ML-DSA-65 (mldsa65) PQC algorithm
$ pqcrypto genpkey -algorithm mldsa44 -out /output/pqc-ca.key
2.2 - Create Key with hexseed
# using OS random function
$ pqcrypto rand -hex 32
[random-hex-output]
# using QRN via API
$ pqcrypto qrn -hex 32
[random-hex-output]
$ pqcrypto genpkey \
-algorithm mldsa65 \
-pkeyopt hexseed:[your-hex-seed] \
-out /output/pqc-ca.key
2.3 - Create Key with password
$ pqcrypto genpkey \
-algorithm mldsa65 \
-aes256 \
-pass pass:mysecret \
-out /output/pqc-ca.key
2.4 - Create Key with hexseed and password
$ pqcrypto rand -hex 32
[random-hex-output]
$ pqcrypto genpkey \
-algorithm mldsa65 \
-aes256 \
-pass pass:mysecret \
-pkeyopt hexseed:[your-hex-seed] \
-out /output/pqc-ca.key
Step 3: Generate Self-Signed PQC CA Certificate
Create a self-signed PQC CA certificate. Replace the placeholder values with your organization's information:
$ pqcrypto req -new -x509 -key /output/pqc-ca.key -out /output/pqc-ca.crt -days 365 \
-subj "/C=US/ST=CA/L=San Jose/O=Your Company/OU=Engineering/CN=<your company name>"
| Field |
Description |
Example |
| C |
Country code (2 letters) |
US |
| ST |
State or province |
CA |
| L |
Locality (city) |
San Jose |
| O |
Organization name |
Your Company |
| OU |
Organizational unit |
Engineering |
| CN |
Common name (FQDN) |
www.example.com |
Caution: Store your PQC CA private key securely. Compromise of the PQC CA key allows an attacker to issue arbitrary certificates.
Step 4: Generate Server Private Key
Generate the server's private key using ML-DSA:
$ pqcrypto genpkey -algorithm mldsa44 -out /output/pqc-server.key
Step 5: Generate Server Certificate Signing Request (CSR)
Create a CSR for the server certificate:
$ pqcrypto req -new -key /output/pqc-server.key -out /output/pqc-server.csr \
-subj "/C=US/ST=CA/L=Fremont/O=Your Company/OU=Engineering/CN=<server-ip or URL>"
The pqc-server.csr file will be created in the directory where you launched Docker (mounted as /output).
Note: The CN (Common Name) should match the domain name that clients will use to connect to your server.
Step 6: Sign Server Certificate with PQC CA
Issue the server certificate by signing the CSR with your PQC CA:
$ pqcrypto x509 -req -in /output/pqc-server.csr -CA /output/pqc-ca.crt -CAkey /output/pqc-ca.key \
-out /output/pqc-server.crt -days 365
After this step, you should have the following files in your local directory:
pqc-ca.key - PQC CA private key (keep secure)
pqc-ca.crt - PQC CA certificate
pqc-server.key - Server private key
pqc-server.csr - Server certificate signing request
pqc-server.crt - Signed server certificate
Step 7: Deploy Certificates to Server
Copy the certificates to your PQCready NGINX AMI instance:
$ scp -i <key-file>.pem pqc-ca.crt pqc-server.crt pqc-server.key ubuntu@<public-ip-or-dns>:/tmp/
Server Configuration
Step 8: Install Certificates
Access EC2 instance:
$ ssh -i <key-file>.pem ubuntu@<public-ip-or-dns>
SSH into your AMI instance and install the certificates:
# Install certificates from /tmp
$ sudo cp /tmp/pqc-server.key /etc/nginx/certs/
$ sudo cp /tmp/pqc-server.crt /etc/nginx/certs/
$ sudo cp /tmp/pqc-ca.crt /etc/nginx/certs/
# Set appropriate permissions
$ sudo chmod 600 /etc/nginx/certs/pqc-server.key
$ sudo chmod 644 /etc/nginx/certs/pqc-server.crt
$ sudo chmod 644 /etc/nginx/certs/pqc-ca.crt
NGINX Configuration
Update your NGINX configuration to use the PQC certificates:
$ sudo vi /etc/nginx/nginx.conf
Configuration
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/certs/pqc-server.crt;
ssl_certificate_key /etc/nginx/certs/pqc-server.key;
ssl_client_certificate /etc/nginx/certs/pqc-ca.crt;
ssl_verify_client on;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
# Prioritize the Hybrid PQC group X25519MLKEM768
# Fall back to a classical group (secp384r1) for compatibility
ssl_conf_command Curves X25519MLKEM768:secp384r1;
# Or, using the older directive for modern OpenSSL builds:
# ssl_ecdh_curve X25519MLKEM768:secp384r1;
location /api/status {
default_type application/json;
return 200 '{"status": "success", "message": "NGINX is alive"}';
}
}
Verify NGINX configuration:
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Start NGINX to apply the configuration:
$ sudo nginx
Stop NGINX:
$ sudo nginx -s stop
Verify NGINX status:
$ ps -eaf | grep nginx
root 1487 1 0 05:34 ? 00:00:00 nginx: master process nginx
www-data 1488 1487 0 05:34 ? 00:00:00 nginx: worker process
root 1490 1028 0 05:34 pts/1 00:00:00 grep --color=auto nginx
Security Group Setup
Add inbound rules: HTTPS(443 - if you configure 443 as nginx port). Set source 0.0.0.0/0 for public access.
Navigate to EC2 → Security Groups → Edit inbound rules → Add rule
| Type |
Protocol |
Port |
Source |
| SSH |
TCP |
22 |
My IP |
| HTTP |
TCP |
80 |
0.0.0.0/0 |
| HTTPS |
TCP |
443 |
0.0.0.0/0 |
Client Certificate Generation (Optional)
For mutual TLS (mTLS) authentication, generate client certificates using the PQCrypto CLI Docker container.
Step 1: Generate Client Private Key
Inside the Docker container:
$ pqcrypto genpkey -algorithm mldsa44 -out /output/pqc-client.key
Step 2: Generate Client CSR
$ pqcrypto req -new -key /output/pqc-client.key -out /output/pqc-client.csr \
-subj "/C=US/ST=CA/L=San Jose/O=Your Company/OU=Client/CN=<your company name>"
Step 3: Sign Client Certificate with PQC CA
$ pqcrypto x509 -req -in /output/pqc-client.csr -CA /output/pqc-ca.crt -CAkey /output/pqc-ca.key \
-out /output/pqc-client.crt -days 365
The client certificate files (pqc-client.key, pqc-client.crt) will be available in your local directory.
Verification
Verify with PQC curl
In the pqcrypto-cli docker, verify connection with PQC curl:
$ curl -i \
--cert /output/pqc-client.crt \
--key /output/pqc-client.key \
--cacert /output/pqc-ca.crt \
https://<server-ip or URL>:443/api/status
HTTP/1.1 200 OK
Server: nginx/1.28.0
Date: Thu, 29 Jan 2026 01:12:18 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 78
Connection: keep-alive
{"status": "success", "message": "NGINX is alive"}
Java Client Certificate Setup
Convert Client Certificates to PKCS12
On pqcrypto-cli docker (You will be prompted to set a password):
$ pqcrypto pkcs12 -export \
-in /output/pqc-client.crt \
-inkey /output/pqc-client.key \
-certfile /output/pqc-ca.crt \
-out /output/pqc-client.p12
Create Java Truststore
On your local machine (exit from pqcrypto-cli):
$ keytool -import \
-alias nginx-ca \
-file pqc-ca.crt \
-keystore truststore.jks
Download Java Client
Download Java Client JAR: https://www.pqcrypto.ai/download/pqc_java_client-1.0.0.jar
You can verify PQCready Nginx connection using java client jar:
# PEM mode
java -jar pqc_java_client-1.0.0.jar --mode pem \
--cert pqc-client.crt --key pqc-client.key --ca pqc-ca.crt \
--host {server-ip} --port 443 --path /api/status
# PKCS12 mode
java -jar pqc_java_client-1.0.0.jar --mode pkcs12 \
--keystore pki/pqc-client.p12 --keystore-password secret \
--truststore pki/truststore.jks --truststore-password secret \
--host {server-ip} --port 443 --path /api/status
Node.js Client
Node.js 24+ recommended
mTLS client code
Example file: pqc_client.js
const https = require('https');
const fs = require('fs');
// Load your mTLS certificates and keys
const options = {
key: fs.readFileSync('./pqc-client.key'),
cert: fs.readFileSync('./pqc-client.crt'),
ca: fs.readFileSync('./pqc-ca.crt'),
rejectUnauthorized: true,
// Skip hostname verification for development/testing
// (cert CN is 'PQCrypto RestGW Server', not 'localhost')
checkServerIdentity: () => undefined,
};
const req = https.request('https://<server-ip or URL>/', options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
let body = '';
res.on('data', (chunk) => {
body += chunk;
});
res.on('end', () => {
console.log('response:', body);
try {
const json = JSON.parse(body);
console.log('parsed JSON:', JSON.stringify(json, null, 2));
} catch (e) {
// not JSON
console.log('Error: ', e.error)
}
});
});
req.on('error', (e) => {
console.error(e);
});
req.end();
Execution
$ node pqc_client.js
statusCode: 200
headers: {
server: 'nginx/1.28.0',
date: 'Fri, 23 Jan 2026 00:28:28 GMT',
'content-type': 'text/html',
'content-length': '615',
connection: 'keep-alive'
}
response: <!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>