NADA 5.6 on AWS User Guide
Overview
This guide covers launching and using the NADA 5.6 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg BI and web analytics listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
NADA is the open source microdata cataloguing platform developed by the International Household Survey Network (IHSN) and the World Bank. National statistics offices, central banks and research institutions use it to publish survey, census and administrative data as a searchable online catalogue, documented with DDI and Dublin Core metadata, with access policies (open, direct download, licensed with an application workflow, or enclave only) for the data files themselves. Everything is also available through a REST API, which tools such as PyNADA and NADAR use.
What the cloudimg image adds:
- A catalogue created on your instance. On first boot the image creates the NADA database, loads the upstream schema, applies the upstream migrations and creates one site administrator, with nothing to click through.
- No web installer, no open sign up. Upstream NADA's installer (
index.php/install) makes whoever reaches it first the administrator. On this image the installer, the legacy upgrade pages and an unauthenticated test page are removed, Apache denies/install, and self registration is switched off until you decide to open it (Step 9). - Secrets unique to your instance. The administrator password, an administrator API key, the MySQL password NADA uses and the session encryption key are generated on first boot and written to
/root/nada-credentials.txt(root only). The image ships with no database and no account, and Apache refuses to start until first boot has finished. MySQLrootsigns in through the local socket only, with no password anywhere. - HTTPS from the first boot. Apache serves NADA on port 443 with a certificate generated on your instance, port 80 redirects to HTTPS, and requests for a host name the instance does not serve get HTTP 421.
- Links that cannot be poisoned. Upstream NADA builds its links from the
Hostheader of each request. This image writes NADA'sbase_urlfrom the instance's own address (or a name you set), and Apache hands NADA that name and the real client address from the connection, never values a client sends. - Only the application on the web. PHP runs only through NADA's front controller. The code (
application/,system/,modules/,vendor/), the data and log directories and the session store are never served, and the upload directories never execute PHP. - Hardened defaults. MySQL listens on
127.0.0.1only (the X Protocol port is off), Apache, MySQL and the first boot service are blocked from the instance metadata service, the AMI requires IMDSv2, and the session cookie isSecureandHttpOnly. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: NADA 5.6 (the upstream v5.6 release, checksum verified), Apache 2.4 with mod_php, PHP 8.3, MySQL 8.0, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
- A security group that allows TCP 22 (SSH) from your admin network, and TCP 443 (NADA) and TCP 80 (redirects to HTTPS) from the networks your users work from. Never open 3306.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick NADA 5.6 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above. The catalogue database and uploaded microdata files live on the root volume, so give it room to grow (30 GiB or more for a production catalogue).
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=30,VolumeType=gp3}' \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=nada}]'
First boot creates the catalogue in well under a minute after the instance is running; the web server starts as soon as it has finished.
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| NADA 5.6 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot creates the catalogue and the secrets, then Apache starts:
systemctl is-active apache2 mysql nada-firstboot
sudo test -f /var/lib/cloudimg/nada-firstboot.done && echo FIRSTBOOT_DONE
All three units are active and the first boot marker is present:
active
active
active
FIRSTBOOT_DONE
Only SSH and Apache listen on network ports; MySQL listens on the loopback address only:
sudo ss -lnt | awk 'NR>1 {print $4}' | grep -v '^127.0.0.5' | sort -u
*:443
*:80
0.0.0.0:22
127.0.0.1:3306
[::]:22
Step 4: Get your URL, password and API key
sudo cat /root/nada-credentials.txt
The file is readable by root only:
# NADA 5.6 - generated on first boot by nada-firstboot.service
# These values are unique to this instance; none was baked into the image. Keep this file secret.
NADA_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
NADA_ADMIN_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/index.php/admin
NADA_ADMIN_EMAIL=admin@cloudimg.local
NADA_ADMIN_PASSWORD=<NADA_ADMIN_PASSWORD>
NADA_API_KEY=<NADA_API_KEY>
NADA_DB_NAME=nada
NADA_DB_USER=nada
NADA_DB_PASSWORD=<NADA_DB_PASSWORD>
# CodeIgniter session encryption key (application/config/config.php); you never need to type it.
NADA_ENCRYPTION_KEY=<NADA_ENCRYPTION_KEY>
# The certificate is self signed (minted on this instance); port 80 redirects to https.
# Change the name NADA is served as: sudo nada-set-hostname <your-dns-name>
# MySQL listens on 127.0.0.1 only; on-box maintenance as root: sudo mysql
# User guide: https://www.cloudimg.co.uk/guides/nada-5-6-on-ubuntu-24-04-aws/
The URL uses the instance's public DNS name from the EC2 instance metadata. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too. If you stop and start the instance without an Elastic IP, the boot service picks up the new address, updates NADA's base_url and issues a new certificate for it. To serve NADA under your own DNS name, see Step 8.
You only need the MySQL password for your own tools; NADA already has it in /var/www/html/nada/application/config/database.php.
Step 5: Sign in
Open the NADA_URL in your browser. The certificate is self signed, so your browser asks you to confirm it the first time (or install your own, Step 8). Choose Login, enter the NADA_ADMIN_EMAIL, then the NADA_ADMIN_PASSWORD from Step 4 (NADA asks for the email first, then the password):

After signing in, open Site administration from the user menu (or browse to the NADA_ADMIN_URL). The dashboard summarises the catalogue, collections, licensed requests and users, and links to every management area:

You can also check the sign in from the instance. This script signs in through the real two step login over HTTPS with the instance's password and reaches the dashboard, shows that a blank password, admin and common weak passwords are refused, then creates a study with the instance's API key, finds it in the public search and deletes it again:
sudo nada-cred-roundtrip.sh
OK per-instance admin signs in over HTTPS (dashboard); blank, admin and weak guesses refused; API key create/search/delete passed; bogus key refused (HTTP 400)
Step 6: Check the versions and the catalogue database
The public version API reports the NADA release:
H=$(sudo grep '^NADA_URL=' /root/nada-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/index.php/api/version"; echo
php -v | head -1
mysql --version
apache2 -v | head -1
{"version":"5.6"}
PHP 8.3.6 (cli) (built: Oct 7 2026 18:06:38) (NTS)
mysql Ver 8.0.46-0ubuntu0.24.04.4 for Linux on x86_64 ((Ubuntu))
Server version: Apache/2.4.58 (Ubuntu)
The schema and the upstream migrations are applied, and exactly one administrator exists, stored with a bcrypt password hash. As root you reach MySQL over the local socket, with no password:
sudo mysql nada -e "SELECT COUNT(*) AS nada_tables FROM information_schema.tables WHERE table_schema='nada'"
sudo mysql nada -e "SELECT u.username, u.email, u.active, LEFT(u.password,4) AS hash, r.name AS role FROM users u JOIN user_roles ur ON ur.user_id=u.id JOIN roles r ON r.id=ur.role_id"
nada_tables
90
username email active hash role
admin admin@cloudimg.local 1 $2a$ admin
Step 7: Publish your first study
Studies can be added in the browser (Studies, Manage studies, Add study, then import a DDI file or fill in the metadata) or through the REST API with the NADA_API_KEY. This example creates a survey study from the instance. The key is read from the credentials file into a request header, so it never appears on a command line:
H=$(sudo grep '^NADA_URL=' /root/nada-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
curl -sk --resolve "$H:443:127.0.0.1" -X POST \
-H @<(sudo grep '^NADA_API_KEY=' /root/nada-credentials.txt | sed 's/^NADA_API_KEY=/X-API-KEY: /') \
-H 'Content-Type: application/json' \
-d '{"repositoryid":"central","published":1,"overwrite":"yes","study_desc":{"title_statement":{"idno":"DEMO-HBS-2026","title":"Household Budget Survey 2026"},"study_info":{"abstract":"Household budget survey measuring income, expenditure and living conditions across urban and rural households.","nation":[{"name":"Example Country","abbreviation":"EXC"}],"coll_dates":[{"start":"2026-01","end":"2026-12"}]},"authoring_entity":[{"name":"National Statistics Office"}]}}' \
"https://$H/index.php/api/datasets/create/survey/DEMO-HBS-2026" | cut -c1-110; echo
{"status":"success","dataset":{"id":"2","doi":null,"repositoryid":"central","type":"survey","idno":"DEMO-HBS-2026"
The study is immediately findable through the public search API:
H=$(sudo grep '^NADA_URL=' /root/nada-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/index.php/api/catalog/search?keywords=household" | grep -o -m1 '"idno":"DEMO-HBS-2026"'
"idno":"DEMO-HBS-2026"
In the browser the public Microdata Catalog lists the published studies with their abstracts, searchable by keyword and filterable by year:

Each study page renders its DDI documentation (identification, producers and sponsors, data collection) with DDI/XML and JSON metadata downloads. The Get Microdata tab shows the access policy you set for its data files:

Curators manage studies, their data files, external resources and access policies under Studies, Manage studies:

Step 8: Your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name NADA is served as. This writes NADA's base_url, mints a new self signed certificate for the name, updates Apache and the URLs in /root/nada-credentials.txt, and keeps the name across reboots:
sudo nada-set-hostname <your-domain>
To use a certificate from a public or internal certificate authority instead (for example one issued by Let's Encrypt for <your-domain>), copy it over the generated pair and reload Apache (running nada-set-hostname again replaces it with a self signed one):
sudo install -m 0644 <your-domain>.crt /etc/ssl/nada/nada.crt
sudo install -m 0600 <your-domain>.key /etc/ssl/nada/nada.key
sudo apache2ctl -t && sudo systemctl reload apache2
Step 9: Users, sign up and e-mail
- Change the administrator password after your first sign in: open the user menu (your name, top right), then Password. Then update or delete
NADA_ADMIN_PASSWORDin/root/nada-credentials.txtso it does not hold an old password. - Add accounts for your curators under Users in Site administration and give each the role they need, rather than sharing the administrator.
- Self registration (researchers creating their own accounts to request licensed data) is off on this image. To open it, set
$config['site_user_register'] = 'yes';in/var/www/html/nada/application/config/config.php(edit it withsudo); NADA then shows a Register link on the login page. Configure e-mail first, so that new accounts can be activated: - E-mail: NADA sends account activation, password reset and data access request messages. Copy
email.sample.phptoemail.phpin/var/www/html/nada/application/config/(ownerroot, groupwww-data, mode 0640, as the other configuration files) and setsmtp_host,smtp_port,smtp_user,smtp_passandsmtp_cryptofor your relay. Amazon SES works as the relay (port 587 withtls); allow outbound 587 in your security group or network ACLs if you restrict egress. - API keys: the image creates one administrator key (
NADA_API_KEY). Users create and revoke their own keys from their profile; you can revoke the image's key there too once you have your own.
Step 10: Security checks
The installer is gone and Apache serves only the application: the code, the data and log directories and the session store are refused, self registration answers 404, plain HTTP redirects to HTTPS and a host name the instance does not serve gets 421. NADA's base_url is the configured name and it trusts no proxy headers:
H=$(sudo grep '^NADA_URL=' /root/nada-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
for p in /index.php/catalog /index.php/install /install/ /index.php/auth/register /application/config/database.php /vendor/autoload.php /datafiles/ /files/sessions/; do
curl -sk -o /dev/null -w "%{http_code} $p\n" --resolve "$H:443:127.0.0.1" "https://$H$p"
done
curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'other host name -> %{http_code}\n' --resolve "example.com:443:127.0.0.1" https://example.com/
sudo grep -E "cloudimg-base-url|^.config\['(site_user_register|cookie_secure|proxy_ips)'\]" /var/www/html/nada/application/config/config.php
200 /index.php/catalog
404 /index.php/install
403 /install/
404 /index.php/auth/register
403 /application/config/database.php
403 /vendor/autoload.php
403 /datafiles/
403 /files/sessions/
http:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
other host name -> 421
$config['base_url'] = 'https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/'; // cloudimg-base-url: set by nada-set-hostname, never from the request
$config['cookie_secure'] = TRUE;
$config['proxy_ips'] = '';
$config['site_user_register'] = 'no';
The certificate was generated on this instance and names its own addresses:
H=$(sudo grep '^NADA_URL=' /root/nada-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = cloudimg
X509v3 Subject Alternative Name:
DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, DNS:ip-<private-ip-dashed>.ec2.internal, IP Address:127.0.0.1, DNS:localhost
Apache (and NADA's PHP code, which runs inside it), MySQL and the first boot service cannot reach the instance metadata service, so a URL NADA is asked to fetch can never return your instance's credentials:
systemctl show apache2 mysql nada-firstboot -p Id -p IPAddressDeny
IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
Id=apache2.service
IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
Id=mysql.service
IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
Id=nada-firstboot.service
Step 11: Backup and maintenance
The catalogue lives in the MySQL database nada (/var/lib/mysql), and the microdata files, external resources and thumbnails you upload live under /var/www/html/nada/datafiles and /var/www/html/nada/files. The simplest backup is an EBS snapshot of the root volume. For a consistent file level copy while NADA is running:
sudo mysqldump --single-transaction --routines nada | gzip > <backup-dir>/nada-$(date +%F).sql.gz
sudo tar -czf <backup-dir>/nada-files-$(date +%F).tar.gz -C /var/www/html/nada datafiles files
Operating system security updates install automatically; run sudo apt-get update && sudo apt-get upgrade to apply everything else. Apache and MySQL restart cleanly and NADA keeps all of its data.
| Component | Path |
|---|---|
| NADA (document root) | /var/www/html/nada |
| Configuration | /var/www/html/nada/application/config/config.php and database.php (mode 0640) |
| Microdata and resource files | /var/www/html/nada/datafiles |
| Database | MySQL database nada (/var/lib/mysql) |
| Apache site | /etc/apache2/sites-available/cloudimg-nada.conf |
| Apache logs | /var/log/apache2/nada-access.log, nada-error.log |
| Certificate and key | /etc/ssl/nada/ |
| Boot service | /usr/local/sbin/nada-firstboot.sh |
| Host name helper | /usr/local/sbin/nada-set-hostname |
| Credentials | /root/nada-credentials.txt (mode 0600) |
| Licence | /usr/share/doc/nada/LICENSE |
Step 12: Security recommendations
- Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your users work from. Never open 3306.
- Use your own DNS name and a certificate your users' browsers trust (Step 8).
- Give each curator their own account and role, and change the administrator password if it may have been shared (Step 9).
- Keep the operating system patched, and snapshot the root volume regularly.
Support and licensing
NADA is open source under the MIT licence (the text ships at /usr/share/doc/nada/LICENSE); there is no per user or per CPU licence fee. The AMI price covers cloudimg's hardening, first boot setup and support. NADA is developed by the International Household Survey Network and the World Bank; cloudimg is not affiliated with or endorsed by them.
- Email: support@cloudimg.co.uk