Skip to content
KodHisar
Menu
TR

HisarBlok · documentation

Installation

From an empty server to a running panel and a published site: what you need, how the web server is set up, what the setup wizard asks, and how updates and backups work.

Features HisarBlok

Source code and a download package are coming soon. This page explains how installation works; the address will be here when the package is published.

What you need

  • PHP 8.4 or newer with dom, pdo_sqlite (SQLite 3.27+), mbstring, zlib and Argon2id support in password_hash(). Optional: gd for image resizing and WebP, openssl for mail over TLS, xmlreader for WordPress imports.
  • nginx or Apache, with PHP-FPM.
  • Nothing else: no Composer step, no npm step and no database server.

php tools/install.php --check prints the same requirement list the wizard shows.

Two addresses, three directories

HisarBlok is a panel that writes a website. The panel and the site are two different things and usually live at two different addresses:

AddressServed directoryRuns PHP?
The panelpanel.example.com…/hisarblok/public/yes, every request
The siteexample.comthe site's own document rootonly /go.php and /get.php, when a module needs them

The third directory is never served: …/hisarblok/data/. It holds all content and every account's password hash (content.sqlite), config.php, backups and the rate-limit file.

The one deployment detail that matters: point the panel's document root at public/, not at the repository. Serve the repository root and data/content.sqlite becomes a download link. The wizard checks this with a real HTTP request before it lets you continue.

The site's document root must be a separate directory the PHP user can write to. It cannot be HisarBlok's own directory and it cannot contain data/; the wizard refuses both.

The web server

nginx. The panel server's root is …/hisarblok/public. The site server serves plain files; only the two visitor endpoints reach PHP:

server {
    server_name example.com;
    root /var/www/example.com/public;
    index index.html;
    error_page 404 /404.html;
    location / { try_files $uri $uri/ =404; }
    location ~ ^/(go|get)\.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.5-fpm.sock;
    }
    location ~ \.php$ { return 404; }
    gzip_static on;
}

Apache. For the panel, DocumentRoot …/hisarblok/public with FallbackResource /index.php; for the site, ErrorDocument 404 /404.html and a PHP handler for go.php / get.php only.

HestiaCP. Add two web domains for the same user: the panel and the site. The code goes one level above the panel domain's public_html, and its public/ directory becomes public_html, so data/ and core/ stay outside what nginx serves. If the domain's PHP sets open_basedir, it must include the panel directory.

Plesk. The code goes inside the subscription, outside httpdocs; the panel subdomain's document root is set to hisarblok/public, and the site's document root is httpdocs. Plesk's default open_basedir covers both.

The setup wizard

With no configuration yet, the panel address opens the setup wizard instead of a sign-in page. Its first question is a setup code: on the first visit the code is written to a file with an unguessable name in the server's data/ directory. That proves whoever fills in the wizard can also read files on the server, so an uploaded-but-unconfigured installation does not belong to whoever finds it first. Wrong codes count against the rate limit, and if data/ is reachable from the web the wizard refuses the code altogether.

Then, in order:

  1. Server check: the requirements, and a real request proving data/ is not served.
  2. Panel language: English or Turkish, changeable later.
  3. Administrator: username, optional email and password. The password is stored in the database as an Argon2id hash; the configuration file never holds it.
  4. First site: domain, name, document root, languages, default language, theme.
  5. Email: an SMTP relay for password resets and notifications, or Skip.
  6. Summary: nothing is written before you press Install.

Install creates the database, the administrator and the configuration, builds the site once and deletes the code file. From then on every one of the wizard's addresses answers 404.

From the command line. tools/install.php does the same without questions. The password is read from standard input rather than passed as an argument, so it never appears in the process list or the shell history.

Check it from outside

After installing, request data/content.sqlite on both the panel and the site address: the answer must be 403 or 404. Behind Cloudflare or another proxy, add the proxy to trusted_proxies in the configuration, or the login rate limit counts the proxy instead of the visitor.

Updating

Take a backup, unpack the new release over the old one, and rebuild the site. data/ is never part of a release, so an update cannot overwrite content or configuration. Database changes apply themselves on the first request after the update.

Backups

A backup is a single .tar.gz holding everything that cannot be regenerated: a consistent copy of the database taken while the site runs, the configuration, module data, each site's uploaded media, and a manifest with the SHA-256 of every file. Built pages are not included; they are rebuilt from the database.

  • tools/backup.php makes a backup, lists them, and reads one through checking every checksum.
  • Backups go to data/backups/, never inside a document root. The newest 14 are kept; the number and the directory can be changed in the configuration.
  • One crontab line for the PHP user gives you a nightly backup; --quiet prints only when something goes wrong.
  • In the panel, System → Backups lists backups, makes one on demand and offers downloads (a download asks for your password again).

Copy your backups off the server. A backup on the same disk does not survive the disk.

Restoring

Restoring replaces the database the panel runs on, so it is done on the server with tools/restore.php, not in the panel, and can be tried first with --dry-run. In order: every checksum and every file name in the archive is checked (a name that would write outside its place is refused); a backup from a newer HisarBlok is refused; the current state is backed up; the database's integrity is checked; only then are the database, configuration, data and media swapped in, and the restore is recorded in the audit log. Then each site is rebuilt.

Moving to another server works the same way: install HisarBlok there, copy the backup into data/backups/, restore it, rebuild the sites and move DNS.