Automatic installation

A ready, secured server, in one command.

The installer starts from a bare Debian 12 and delivers a live site: database, application service, Nginx, TLS certificate, firewall, backups, monitoring. It asks its questions up front, then runs fifteen steps without you. And it leaves behind a server that maintains itself.

Fifteen steps, all re-runnable

Site name, domain, admin account, certificate, SSH key: everything is asked before starting, then summarised for confirmation. After that, nothing more to type. Every step is idempotent — if one fails, you fix the cause and run the same command again, without undoing anything.

[00] Pre-flight checks
[01] Hardening: firewall, SSH, fail2ban, sysctl, auto-updates
[02] System account, directories and permissions
[03] System dependencies
[04] PostgreSQL — service and hardening
[05] Database and application role
[06] Memcached
[07] Python environment
[08] JEIKO package and update mechanism
[09] Django configuration (.env, settings, urls)
[10] Gunicorn service
[11] Nginx
[12] Let's Encrypt certificate and HTTPS
[13] Backups and monitoring
[14] Migrations, static files, health check

  1. Several sites per server. Each gets its own Unix account, database, service and backups; a flaw in one gives no access to the others.
  2. Secrets are generated, not chosen. Django's secret key and, if you leave the field empty, the PostgreSQL password (forty characters) are drawn at random. The admin account's password is used once and stored nowhere.
  3. The admin account can sign in right away: its address is recorded as verified in the last step.

Server security, set up by default

A server exposed to the Internet is probed within the hour. The installer applies the protections people forget when configuring by hand.

  1. Firewall. Everything inbound is closed, except SSH, HTTP and HTTPS (ports 22, 80 and 443).
  2. SSH. The installer offers to add your public key, then to turn off password login — two separate decisions, so you never lock yourself out. The choice is remembered for later sites. Afterwards, one command adds a key and checks the configuration before applying it.
  3. Fail2ban. Three failed SSH logins in ten minutes: the address is banned for an hour. An address that exceeds the rate limits twenty times in five minutes is banned for two hours.
  4. Rate limits in Nginx. Five login attempts per minute per address, ten bookings or writes per minute, thirty requests per second for everything else. A normal visitor never reaches them.
  5. A confined service. The site runs under an account with no shell and no home directory, in a systemd service that sees neither /home nor anyone else's /tmp, and cannot rewrite the system.
  6. Secrets in one place. The site's credentials live in a file readable by root only; the site's .env is readable only by its own account.
  7. Uploaded files never execute. An .html, .svg or .js file sent through a form is served as a download, in a sandbox — not as a page of the site. .env, .sql, .bak and hidden files are refused.
  8. Serious HTTPS. TLS 1.2 and 1.3 only, HSTS, security headers (nosniff, framing limited to the site, referrer policy, restricted browser permissions).

One-click updates that know how to roll back

In the admin, « Update JEIKO » shows the available version, then the live log; the page survives the site's restart. Behind that button, the application only triggers: the script that runs belongs to root and lives outside the site, where the site cannot change it. The site's account is allowed two commands, nothing else.

How an update runs

1. read the version manifest
2. check the package's sha256 fingerprint
3. back up the database (pg_dump)
4. install the package
5. realign settings.py and urls.py
6. Django check, migrations, static files
7. permissions, restart
8. site health check

→ any error after step 4: previous version reinstalled,
templates restored, database restored if migrations ran.

  1. A package whose fingerprint doesn't match is not installed. It is the only link of trust between what is published and what runs on your server.
  2. Two updates never overlap: a lock serialises them.
  3. Your settings are never lost. settings.py is copied over with each version; everything specific to the site — keys, domain, email, payment — comes from the .env, which updates don't touch.

A server that maintains itself

A small server rarely fails for an exotic reason: a full disk, an expired certificate, a backup that had stopped running. None of these give warning. So the installer sets up the routine nobody ever has time to keep.

  1. Debian security patches, downloaded and installed every day. After a kernel update, the machine reboots at 4:20 am and the site comes back on its own.
  2. Daily backup of the database, media and configuration, at a time offset per site. Every dump is checked; an incomplete backup is deleted rather than passing for a valid one. Thirty days kept, plus an encrypted off-server copy if you give a destination.
  3. Health check every morning at 7:30: disk space, memory, certificate expiry, service status, age of the last backup.
  4. Certificate renewal, automatic, tested at installation.

The commands, if you want control

sudo jeiko-backup mysite # on-demand backup
sudo jeiko-verifier # server health
sudo jeiko-client-update mysite --check
sudo jeiko-server-update mysite # realign the server configuration

Server configuration evolves too: a new installer version replays onto an existing site, which converges to what a fresh install would produce — without touching the database or the data.

Install a siteApplication security