Two things stand between a freshly installed Loghound and the internet: a screen that tells you exactly what is wrong with the machine, and a token in a file only its administrator can read.
The first screen the browser installer shows is one row per requirement, with the exact command that fixes anything not passing, written for the user PHP is actually running as on this machine. For example, if the service user cannot read your access logs:
setfacl -m u:loghound:rx /var/log/apache2 setfacl -m u:loghound:r /var/log/apache2/example_com_access.log
Read that table before continuing. A green check here is the difference between “the daemon is running” and “the daemon is running and indexing something”.
If you are behind open_basedir
The panel’s PHP pool is allowed to read /var/log, /etc/apache2 and /etc/nginx on purpose, because that is where your logs and the lines that name them live. If you tightened the pool, this screen cannot see those directories and says exactly that. Widen open_basedir for them, or run bin/loghound-setup in a shell, where the restriction does not apply. Where it installs, and the modes has the pool settings.
Before the installer accepts anything that will be written to the configuration, it asks you to paste a token from a file only this server’s administrator can read:
sudo cat /opt/loghound/var/install-token
Until DNS points somewhere else your URL is reachable by anyone, and without the token whoever found it first could point Loghound at a Solr they control and set the password. It is the same mechanism Grafana, Matomo and phpMyAdmin use. Guessing is rate limited, and the token file is deleted the moment setup finishes.
The status page itself stays readable without the token, and that is deliberate: you have to be able to see a permission problem in order to go and fix it. Nothing can be saved until it is entered.
There is one exception to being asked for it at all. Confirming Start over inside a signed-in panel session (which deletes both indexes) carries that proof into the installer, so you are not sent back to the server for a token; it lasts half an hour, it is used once, and it belongs to that browser alone. Anyone else reaching the installer still has to read the file over a shell.
- It is unreachable once a valid configuration exists.
- Nothing is written until the token — a
0600file — has been pasted. - Every state-changing request carries a CSRF token, and no privileged action happens on a GET.
- Steps cannot be reached out of order by guessing a URL; a step whose prerequisites are unmet redirects to the first incomplete one.
- No secret is rendered anywhere — not the API key, the beacon signing key, the address salt or the password, and not into a hidden field, a URL, a job payload, a log line or an error message. Where it matters that one is set, the screen says “stored”.
- Sample log lines are attacker-controlled bytes by definition, are displayed on purpose, and are escaped on the way out. The page’s Content-Security-Policy is
script-src 'self'with no inline scripts. - A hand-typed log path is resolved with
realpath()and refused unless it is insideallowed_log_roots; a custom pattern is refused unless it compiles and runs fast.
Installing
- Install from a shell
- Where it installs, and modes
- Install from a browser
- System check & setup token
- Unattended installs
- Upgrading