Install & upgrade
troubleshooting

The installer stops at the first command that fails, so a failure often looks like nothing at all. Find the message you saw below — the answers say what the installer was doing at that moment and what to run instead.

Start here

The installer stopped and printed nothing useful

The script runs with set -e: the first command that fails ends the run immediately, and the failing command's own error may have scrolled past. Run it again with a trace, and keep the last lines:

curl -fsSL https://raw.githubusercontent.com/jasoncheng7115/jt-wazuh-mgr/main/install.sh -o /tmp/jt-install.sh
sudo bash -x /tmp/jt-install.sh 2>&1 | tail -40

The last + line before the error is the exact command that failed. Match it against the sections below.

What the installer touches, so you know what to check

  • /opt/jt-wazuh-mgr/ — program files, rule packs, and your config.yaml
  • /etc/systemd/system/jt-wazuh-mgr.service — the service unit, rewritten on every run
  • Python packages from requirements.txt, installed with pip
Your configuration is safe. config.yaml is downloaded only when it does not already exist. Upgrading never overwrites it.

Where does it have to be installed?

On the Wazuh Manager itself — and on the master node if you run a cluster. The tool reads the ruleset and the manager's own files from /var/ossec, so it cannot manage a manager from somewhere else.

Check you are on a manager, not an agent:

/var/ossec/bin/wazuh-control info
ls /var/ossec/etc/rules/    # managers have this; agents do not

Downloads fail

curl: (6) Could not resolve host / (7) Failed to connect

curl: (6) Could not resolve host: raw.githubusercontent.com

The manager has no route to GitHub. That is normal — plenty of Wazuh managers sit on an isolated network on purpose. Two ways forward:

  • If a proxy exists, set it before running the installer:
    export https_proxy=http://proxy.example.com:3128
    export http_proxy=$https_proxy
    curl -fsSL https://raw.githubusercontent.com/jasoncheng7115/jt-wazuh-mgr/main/install.sh | sudo -E bash
    sudo -E matters — without it sudo drops the proxy variables.
  • If there is no route at all, use the offline install below.

curl: (60) SSL certificate problem

curl: (60) SSL certificate problem: unable to get local issuer certificate

Usually one of two things: the CA bundle is out of date, or a corporate appliance is intercepting TLS and presenting its own certificate.

# refresh the CA bundle
sudo apt update && sudo apt install --reinstall ca-certificates   # Debian / Ubuntu
sudo dnf reinstall ca-certificates                                  # RHEL / Rocky

If an appliance is inspecting traffic, add its CA to the system store rather than disabling verification. Do not use curl -k for an installer — you would be downloading code you cannot authenticate.

Installed, but the Rule Packs tab is empty

Rule pack files are downloaded on a best-effort basis: if the index or a file cannot be fetched, the installer says so and carries on rather than failing the whole install.

- packs (skipped, index unavailable)

Re-run the installer once connectivity is back. Nothing else needs undoing.

Python dependencies

error: externally-managed-environment

error: externally-managed-environment × This environment is externally managed

Debian 12, Ubuntu 23.04 and later refuse pip install into the system Python, to stop pip and the distribution's package manager fighting over the same files. This is the single most common reason an install or upgrade stops on a current OS.

Pick one, in this order of preference:

  1. Install the dependencies as distribution packages. Cleanest, and it survives OS upgrades:
    sudo apt install python3-flask python3-requests python3-yaml
    Then re-run the installer — pip will find everything already present.
  2. Tell pip you accept the risk, if the distribution packages are too old:
    sudo pip install --break-system-packages -r /opt/jt-wazuh-mgr/requirements.txt
    sudo systemctl restart jt-wazuh-mgr
    The flag is named honestly: pip may replace files the package manager owns.
  3. Use a virtual environment if you want full isolation — see running from a virtual environment.

pip: command not found

install.sh: line 107: pip: command not found

Many systems ship pip3 without a pip alias, and some ship neither. Install it, then re-run the installer:

sudo apt install python3-pip     # Debian / Ubuntu
sudo dnf install python3-pip     # RHEL / Rocky / Alma

If your policy forbids pip entirely, install the three dependencies as distribution packages instead — see the previous answer.

pip cannot reach PyPI

WARNING: Retrying ... Connection to pypi.org timed out

Same isolation as the download failures above, at a later step. The program files are already in place at this point; only the dependencies are missing. Install them from your distribution's packages, or from wheels you copy in yourself — see offline install.

Running from a virtual environment

If you prefer to keep everything out of the system Python:

sudo python3 -m venv /opt/jt-wazuh-mgr/venv
sudo /opt/jt-wazuh-mgr/venv/bin/pip install -r /opt/jt-wazuh-mgr/requirements.txt

Then point the service at it with a drop-in, which survives future upgrades:

sudo mkdir -p /etc/systemd/system/jt-wazuh-mgr.service.d
sudo tee /etc/systemd/system/jt-wazuh-mgr.service.d/override.conf <<'EOF'
[Service]
Environment=PATH=/opt/jt-wazuh-mgr/venv/bin:/usr/bin:/bin
EOF
sudo systemctl daemon-reload && sudo systemctl restart jt-wazuh-mgr

The service will not start

Read the actual reason first

Two commands say what went wrong; almost every answer below comes from them:

systemctl status jt-wazuh-mgr --no-pager -l
journalctl -u jt-wazuh-mgr -n 50 --no-pager

ModuleNotFoundError: No module named 'flask'

ModuleNotFoundError: No module named 'flask'

The files installed but the dependencies did not — the pip step failed earlier, and with set -e you may not have noticed. Go back to Python dependencies, then:

sudo systemctl restart jt-wazuh-mgr

Address already in use / nothing answers on port 5000

OSError: [Errno 98] Address already in use

Something else holds the port. Find it:

sudo ss -tlnp | grep :5000

Either stop that service, or move this one with a drop-in so an upgrade will not undo it:

sudo mkdir -p /etc/systemd/system/jt-wazuh-mgr.service.d
sudo tee /etc/systemd/system/jt-wazuh-mgr.service.d/override.conf <<'EOF'
[Service]
ExecStart=
ExecStart=/opt/jt-wazuh-mgr/wazuh_agent_mgr.py --web --ssl-auto --port 5443
EOF
sudo systemctl daemon-reload && sudo systemctl restart jt-wazuh-mgr

The empty ExecStart= is required: it clears the original line before the new one is added.

The service starts but the browser cannot connect

Work outwards from the machine itself. If the first command answers and the second does not, it is the firewall, not the tool:

curl -kIs https://127.0.0.1:5000/ | head -1      # on the manager
sudo firewall-cmd --add-port=5000/tcp --permanent && sudo firewall-cmd --reload   # RHEL family
sudo ufw allow 5000/tcp                                                            # Ubuntu

Note the URL is https. With --ssl-auto the tool serves the Wazuh dashboard's own certificate when the dashboard runs on the same host (1.11.3 and later); otherwise the certificate is self-signed and the browser warns once.

"Connection Lost" right after opening the Wazuh dashboard

Chrome and Edge keep your "proceed anyway" for a self-signed certificate per host, not per port, and drop it the moment they see a valid certificate on that host. When the dashboard runs on the same machine with a certificate your browser trusts, opening it cancels the exception the tool was using: every request then fails in the TLS handshake, the page shows Connection Lost, and the tool's log shows nothing, because nothing arrives. Pressing F5 brings the certificate warning back. Firefox is not affected.

Upgrade to 1.11.3 or later and keep --ssl-auto: the tool then serves the dashboard's certificate, so there is no exception to lose. With your own certificate, use one your browsers trust:

./wazuh_agent_mgr.py --web --ssl-cert /path/to/cert.pem --ssl-key /path/to/key.pem

If instead the page says Session expired and returns to the login page, the Wazuh API revoked the token. Look for DELETE /security/user/authenticate or PUT /security/user/revoke in /var/ossec/logs/api.log at that moment, and log in to the tool with an API user of its own rather than the dashboard's wazuh-wui.

Upgrades

The upgrade finished but the version did not change

Read the version back from the installed path rather than trusting the installer's summary line:

grep __version__ /opt/jt-wazuh-mgr/lib/__init__.py
systemctl is-active jt-wazuh-mgr

If the file says the new version but the interface still shows the old one, clear stale bytecode and restart:

sudo rm -rf /opt/jt-wazuh-mgr/lib/__pycache__
sudo systemctl restart jt-wazuh-mgr

Then reload the browser with cache bypassed (Ctrl+Shift+R).

My customised service file was replaced by the upgrade

Known behaviour. Every run copies the shipped unit over /etc/systemd/system/jt-wazuh-mgr.service. Any edit you made directly to that file — a different port, a User=, an Environment= line — is lost on the next upgrade.

Restore it once, then make the change survive by moving it into a drop-in, which the installer never touches:

sudo mkdir -p /etc/systemd/system/jt-wazuh-mgr.service.d
sudo tee /etc/systemd/system/jt-wazuh-mgr.service.d/override.conf <<'EOF'
[Service]
Environment=PYTHONPATH=/opt/jt-wazuh-mgr/vendor
EOF
sudo systemctl daemon-reload && sudo systemctl restart jt-wazuh-mgr

Check what is in effect afterwards with systemctl cat jt-wazuh-mgr.

Will an upgrade touch my configuration or my installed rule packs?

No. config.yaml is skipped when it already exists. Rule packs you have installed live in the Wazuh manager's own directories (/var/ossec/etc/rules, etc/lists, etc/decoders) with their state in /var/ossec/etc/jt-packs/; upgrading the tool only refreshes the catalogue it offers you.

When the refreshed catalogue holds a newer version of a pack you installed, the Rule Packs tab offers Update next to it (1.12.0 and later). It shows what will change first, leaves the lists you maintain and any file you edited as they are unless you choose otherwise, and lists the agent-side steps that are new since your version. Reload the ruleset on every node afterwards.

Going back to the previous version

Take a copy before upgrading and you can always return to it:

sudo tar czf /root/jt-wazuh-mgr-backup-$(date +%F).tar.gz -C /opt jt-wazuh-mgr
# to roll back
sudo systemctl stop jt-wazuh-mgr
sudo tar xzf /root/jt-wazuh-mgr-backup-YYYY-MM-DD.tar.gz -C /opt
sudo systemctl start jt-wazuh-mgr
Use -C. Extracting without it unpacks into the current directory, and a later version check can read the wrong copy and report success while nothing changed.

Offline and air-gapped installs

How do I install or upgrade when the manager has no internet access?

Build one archive on a machine that has internet access — the release plus the Python wheels for the manager's Python version — copy it over, and run the installer from it:

tar xzf /root/jt-wazuh-mgr-X.Y.Z-offline.tar.gz -C /root
sudo bash /root/jt-wazuh-mgr-X.Y.Z/install.sh --offline

With --offline the installer copies everything from the extracted directory and installs the wheels from its wheels/ directory into /opt/jt-wazuh-mgr/vendor; it never runs curl, apt or dnf, and pip is optional. Upgrades work the same way and keep config.yaml.

The full procedure — building the archive, matching the Python version, verifying, upgrading, rolling back and the manual steps for v1.19.0 and earlier — is on its own page: Offline install & upgrade.

Installed, but something is wrong

The login page appears but the credentials are rejected

The username and password are a Wazuh API user, not an operating system account and not your dashboard login. Confirm the API answers first:

curl -k -u <user>:<password> https://127.0.0.1:55000/security/user/authenticate

The password generated at installation time is inside wazuh-install-files.tar, in whichever directory you ran the Wazuh installer from. To create a dedicated account for this tool:

sudo /opt/jt-wazuh-mgr/create_api_user.py

The configuration editor has no syntax highlighting

The editor component is loaded from a CDN, so it is unavailable on an isolated network. Editing still works; only the colouring is missing. Nothing needs fixing.

Removing it completely

sudo bash /opt/jt-wazuh-mgr/uninstall.sh

Rule packs you installed into the manager are not removed by this — remove those from the Rule Packs tab first if you want them gone, so that the original files are restored properly.

Still stuck

What to include when you ask

These four make almost any install problem diagnosable at a glance:

cat /etc/os-release | head -2
python3 -V
grep __version__ /opt/jt-wazuh-mgr/lib/__init__.py
journalctl -u jt-wazuh-mgr -n 50 --no-pager

Plus the last 40 lines of bash -x output from the first answer on this page. Open an issue at github.com/jasoncheng7115/jt-wazuh-mgr/issues.

Before you paste. Logs from a Wazuh manager carry host names and addresses from your estate. Replace anything you would not put on a public page.
No answer matches that. Try a word from the error message itself.