Documentation

Manual NQ2 installation on Linux

Commands for Ubuntu and Raspberry Pi OS: Node.js 24, NQ2, PM2, optional Nginx, MQTT and Zigbee2MQTT.

Oct 25, 2026 · Reading time: 10 min

Perform the steps yourself instead of running the NQ2 installer. These commands match the current installer defaults: NQ2 latest and Zigbee2MQTT 2.14.2.

Order: dependencies → NQ2 → Nginx → Mosquitto → Zigbee2MQTT. NQ2 and common dependencies are required. Nginx, Mosquitto and Zigbee2MQTT are optional and enabled by default. Skip sections marked “optional” to omit a component. Without Nginx, use port 8080. Without Mosquitto, use an existing broker and enter its address and credentials in Zigbee2MQTT configuration. Common tools (Node.js, PM2, Corepack and build tools) are installed first; Zigbee2MQTT npm dependencies and compilation follow its source download at the end.

1. Check the existing system

This guide is for a new application installation on running Ubuntu 22.04/24.04 or Raspberry Pi OS / Debian 12 or 13 with systemd. Raspberry Pi OS Lite 64-bit on a Raspberry Pi 4 is the example. Execute commands in Bash on the target device as a regular sudo-enabled user, not root. Internet access and a working network are required; for SSH, sign in with your existing account.

If you do not have an OS yet, follow steps 1–13 of the card guide, set the account, network and SSH, then boot the Pi without adding the NQ2 script and return here. Do not run raspianimager.cmd or install.sh alongside this method. Alternatively, use the existing-system installer.

Inspect existing services and ports before running commands. This is not an upgrade of an existing NQ2 installation. /opt/nq2 and (if installing Zigbee2MQTT) /opt/zigbee2mqtt must be unused. If you already use Nginx or Mosquitto, preserve their configuration and skip the relevant sections rather than overwriting active files. You need Python 3.10+ and hardware supported by Node.js 24 and the application’s dependencies. A Zigbee coordinator is required only for Zigbee2MQTT.

If a command fails, stop and resolve the cause before continuing. Set your own passwords before first starting the application. First check the account and architecture:

whoami
dpkg --print-architecture
hostname

2. Install packages and Node.js 24

These commands install dependencies and download the NodeSource repository setup script. You can inspect it with less before running it (press q to exit). It is a third-party setup script, not the NQ2 installer. Node.js is fixed to major version 24, matching the current installer. The manual steps also use the additional unzip and nano packages.

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg git make g++ gcc libsystemd-dev avahi-daemon libnss-mdns logrotate unzip nano openssl python3
curl -fsSL --retry 3 -o "$HOME/nodesource-setup-24.sh" https://deb.nodesource.com/setup_24.x
less "$HOME/nodesource-setup-24.sh"
sudo bash "$HOME/nodesource-setup-24.sh"
sudo apt-get install -y nodejs
sudo sh -c 'umask 022; npm install -g corepack pm2'
sudo corepack enable
corepack prepare [email protected] --activate
sudo systemctl enable --now avahi-daemon
node --version
pm2 --version

Wi-Fi: disable power saving

If the Raspberry Pi or Linux server uses Wi-Fi, disable Wi-Fi power saving to address intermittent disconnections after idle periods. The device can appear switched off while it is still running. The current NQ2 installer configures this automatically on systems using NetworkManager. For a manual installation or an older bundle, follow the Wi-Fi configuration and verification guide. Ethernet does not require this Wi-Fi change.

3. Download NQ2 latest and run npm install

The latest ZIP is dynamic, so this guide does not pin a fixed archive checksum. After extraction run npm install as your regular user. The commands below locate package.json even inside a wrapper folder. If downloading returns 404, the archive has not been published: stop installation. /opt/nq2 must not already exist.

mkdir "$HOME/nq2-manual-download"
cd "$HOME/nq2-manual-download"
curl -fL --retry 3 -o nq2.zip https://nq2.io/api/apps/nq2-local/download.zip
unzip nq2.zip -d unpack
sudo mkdir /opt/nq2
sudo chown "$(id -un):$(id -gn)" /opt/nq2
python3 - <<'PYCODE'
from pathlib import Path
import shutil
root = Path('unpack')
packages = [p.parent for p in root.rglob('package.json') if 'node_modules' not in p.relative_to(root).parts]
if not packages: raise SystemExit('No package.json in NQ2 ZIP')
depth = min(len(p.relative_to(root).parts) for p in packages)
packages = [p for p in packages if len(p.relative_to(root).parts) == depth]
if len(packages) != 1: raise SystemExit('Ambiguous NQ2 package root')
shutil.copytree(packages[0], '/opt/nq2', dirs_exist_ok=True)
PYCODE
cd /opt/nq2
npm install --no-audit --no-fund

4. Configure NQ2 in .env

Create .env in the application directory /opt/nq2. Use KEY=value syntax, without JSON braces or commas. NQ2 reads this file at startup. The application administrator account is separate from SSH and MQTT.

cd /opt/nq2
umask 077
cat > .env <<'EOF'
NODE_ENV=production
PORT=8080
[email protected]
ADMIN_PASSWORD=admin123
EOF
chmod 600 .env
nano .env

Before first start, set your own administrator email and password. In nano, save with Ctrl+O, Enter and exit with Ctrl+X. Quote passwords containing # or spaces. Do not distribute this file.

5. Start NQ2 in PM2 and enable startup

Run PM2 commands as the same regular account. Start the application from its directory, save the process list and register PM2 for systemd startup:

cd /opt/nq2
pm2 start index.js --name nq2
pm2 save
sudo env PATH="$PATH" pm2 startup systemd -u "$(id -un)" --hp "$HOME"
sudo mkdir -p "/etc/systemd/system/pm2-$(id -un).service.d"
sudo tee "/etc/systemd/system/pm2-$(id -un).service.d/network.conf" > /dev/null <<'EOF'
[Unit]
Wants=network-online.target
After=network-online.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable "pm2-$(id -un)"
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:workerInterval 30
pm2 save
pm2 list

PM2 remembers the application working directory. Configure startup once for this user; a later pm2 save also includes Zigbee2MQTT added at the end. Do not use sudo pm2 start or sudo pm2 save. PM2 startup documentation.

Remove initial administrator settings after signing in

After the first startup and a successful sign-in to NQ2, remove ADMIN_EMAIL and ADMIN_PASSWORD from the application’s .env file. They are needed only during the first startup to create the administrator account. Keep the runtime settings, for example:

NODE_ENV=production
PORT=8080

Edit /opt/nq2/.env on Linux or C:\ProgramData\NQ2\apps\nq2\.env on a default Windows installation. Do this after confirming that your administrator login works.

6. Limit other logs

pm2-logrotate handles application logs. These settings also rotate the PM2 daemon log and limit the system journal.

sudo tee /etc/logrotate.d/nq2-pm2 > /dev/null <<EOF
$HOME/.pm2/pm2.log {
    su $(id -un) $(id -gn)
    daily
    maxsize 10M
    rotate 7
    compress
    missingok
    notifempty
    copytruncate
}
EOF
sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/nq2.conf > /dev/null <<'EOF'
[Journal]
SystemMaxUse=100M
RuntimeMaxUse=50M
EOF
sudo systemctl restart systemd-journald

7. Nginx — port 80 to NQ2 on 8080 — optional

This block assumes a fresh system without other Nginx sites. proxy_pass forwards requests to NQ2 without changing the browser address. Restart Nginx only after nginx -t succeeds. Avahi advertises the .local hostname.

sudo apt-get install -y nginx
sudo tee /etc/nginx/sites-available/nq2 > /dev/null <<'EOF'
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 300s;
    }
}
EOF
sudo rm -f /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/nq2 /etc/nginx/sites-enabled/nq2
sudo nginx -t
sudo systemctl enable nginx avahi-daemon
sudo systemctl restart nginx avahi-daemon

8. Mosquitto — MQTT username and password — optional

This example uses the MQTT username nq2; change it in the command if needed. mosquitto_passwd asks for the password twice. Enter your own password or nq2 to use the package default. Use the same credentials in Zigbee2MQTT. Use -c only when creating the password file on a fresh system: it overwrites an existing password file. Mosquitto authentication documentation.

By default, the broker listens only on 127.0.0.1:1883 and requires authentication, matching mqtt_allow_remote: false in config.yaml. In a manual installation, to allow other computers, replace listener 1883 127.0.0.1 below with listener 1883 0.0.0.0. Clients use the server IP and MQTT credentials. The equivalent installer option is mqtt_allow_remote: true. Editing config.yaml alone does not change an already installed broker. This does not assign a public IP address, configure router forwarding or change existing firewall rules.

sudo apt-get install -y mosquitto mosquitto-clients
sudo mosquitto_passwd -c /etc/mosquitto/nq2.passwd nq2
sudo chown root:mosquitto /etc/mosquitto/nq2.passwd
sudo chmod 640 /etc/mosquitto/nq2.passwd
sudo tee /etc/mosquitto/conf.d/nq2.conf > /dev/null <<'EOF'
listener 1883 127.0.0.1
allow_anonymous false
password_file /etc/mosquitto/nq2.passwd
EOF
sudo systemctl enable mosquitto
sudo systemctl restart mosquitto
sudo systemctl is-active mosquitto
sudo tee "/etc/systemd/system/pm2-$(id -un).service.d/network.conf" > /dev/null <<'EOF'
[Unit]
Wants=network-online.target mosquitto.service
After=network-online.target mosquitto.service
EOF
sudo systemctl daemon-reload

9. Install Zigbee2MQTT 2.14.2 — optional

Access to the Zigbee coordinator

Add your account to dialout. Then disconnect from SSH and log back in using the same account so the new group membership takes effect.

sudo usermod -aG dialout "$(id -un)"
exit

After reconnecting over SSH, continue installation as the same account. Skip the dialout group step for a network coordinator.

Download and dependencies

Version 2.14.2 matches the current package. Run pnpm without sudo, using your Imager account. Corepack reads the package manager version from the repository and may ask to download it on first use. Zigbee2MQTT installation documentation.

sudo git clone --depth 1 --branch 2.14.2 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
sudo chown -R "$(id -un):$(id -gn)" /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
pnpm install --frozen-lockfile
pnpm run build
mkdir -p data
nano data/configuration.yaml

10. Configure Zigbee2MQTT — optional

Paste this configuration into the editor. Set user and password to the broker credentials from step 8. In nano, save with Ctrl+O, Enter and exit with Ctrl+X. Inside a single-quoted YAML password, escape an apostrophe by doubling it, for example 'password''with apostrophe'. After saving, run chmod 600 /opt/zigbee2mqtt/data/configuration.yaml.

onboarding: true allows you to select the coordinator on first start. Use a stable /dev/serial/by-id/... path and the correct adapter type (such as ember or zstack, depending on the hardware).

version: 5
onboarding: true
mqtt:
  server: mqtt://127.0.0.1:1883
  base_topic: zigbee2mqtt
  user: 'nq2'
  password: 'nq2'
frontend:
  enabled: true
  host: 0.0.0.0
  port: 8090
advanced:
  log_output: [console]
  network_key: GENERATE
  pan_id: GENERATE
  ext_pan_id: GENERATE

11. Start Zigbee2MQTT in PM2 — optional

Only now add Zigbee2MQTT to PM2 using the same account as NQ2. Z2M_ONBOARD_URL sets the first-run onboarding screen to port 8090. Skip this step if you are not installing Zigbee2MQTT.

cd /opt/zigbee2mqtt
export Z2M_ONBOARD_URL="http://0.0.0.0:8090"
pm2 start index.js --name zigbee2mqtt
pm2 save
unset Z2M_ONBOARD_URL
pm2 list

NQ2 remains running. The PM2 startup service from step 5 is shared by both applications; do not register it again. pm2 save records the list containing nq2 and zigbee2mqtt for restoration at boot.

12. Check operation and reboot

Without Nginx, the NQ2 address is http://nq2.local:8080 (use your actual hostname). If Zigbee2MQTT is disabled, skip its port 8090 and coordinator checks.

If the Imager hostname is nq2, open http://nq2.local for NQ2 and http://nq2.local:8090 for Zigbee2MQTT. Substitute your actual hostname if different. You can also use the IP address shown by your router. .local requires mDNS support on the client. Complete coordinator selection and MQTT setup from step 8 in Zigbee2MQTT. A missing coordinator or incorrect adapter type may prevent Zigbee from starting.

Check processes and the NQ2 HTTP response below. Then reboot the Pi, log back in and repeat pm2 list and the checks of both web interfaces.

pm2 list
sudo systemctl is-active avahi-daemon
curl -I http://127.0.0.1:8080/
sudo reboot

13. Troubleshooting and changing settings

Use the commands below to inspect application logs; press Ctrl+C to stop following. After editing settings in /opt/nq2/.env, run:

pm2 restart nq2
pm2 save

NQ2 reads .env again. Set ADMIN_EMAIL and ADMIN_PASSWORD before first start; editing them later is not a reset procedure for an existing administrator account. After changing Zigbee2MQTT configuration, use pm2 restart zigbee2mqtt and pm2 save. Do not use sudo pm2 list: it accesses another user’s process list.

This manual method does not create the nq2-firstboot service or automatically retry installation. After an interruption, return to the incomplete step; inspect existing directories and password files before repeating commands that create them. An interrupted package installation may require sudo dpkg --configure -a and sudo apt-get -f install before retrying the failed step. Diagnose system account and network issues separately: this guide does not configure them. Do not distribute files containing your credentials or your private prepared card.

pm2 logs nq2 --lines 100
pm2 logs zigbee2mqtt --lines 100
sudo journalctl -u mosquitto -n 100 --no-pager
sudo journalctl -u nginx -n 100 --no-pager
sudo journalctl -u "pm2-$(id -un)" -n 100 --no-pager