Installation & Setup

This page walks you through a complete installation of EternalSystem on your own server – from the requirements and the API's setup wizard to a finished cloud with proxy, lobby and an entered license.

Note

EternalSystem consists of three parts: the plugin jar (one jar for Spigot/Paper and the proxy, see Modules & Presets), the REST API including the Eternal Cloud node (starts the proxy and servers itself, replaces CloudNet) and the dashboard (the Angular web interface). API/cloud and dashboard often run on separate hosts – that is the recommended setup.

Overview

PartWhat it isRuns where
Plugin jar (Eternal-<ver>.jar)All game modules in one jar, also for the proxyIn every game server / proxy (distributed by the cloud)
REST API + cloud node (EternalApi-<ver>.jar)Database access for the dashboard, starts and manages the serversOn the host that runs the servers (as root)
Dashboard (eternal-web-<ver>.zip)Web interface for moderation, cloud, license etc.Separate web host with Apache/nginx

Requirements

  • A Linux host (Debian/Ubuntu or similar). The cloud starts the game servers there.
  • Java 21 or newer to start the API (java -version). The cloud installs the JDKs for the game servers itself later – no system Java is needed for that.
  • MySQL or MariaDB. Mandatory for a network, because all servers share the same database. H2 (file) is only for trying things out with a single server.
  • A domain for the dashboard and a reverse proxy (Apache or nginx) in front of it, ideally with HTTPS.
  • Open ports: the Minecraft proxy port (default 25565) to the outside, 443 for the dashboard. The API (7070) and the backend servers stay internal.
Warning

The API runs as root – it installs JDKs and may bind low ports. The game servers themselves should not run as root; that is what run-as-user is for (below). Background and the complete threat model are in Security.

1. Get the jars from the release repo

The binaries are publicly available in the release repo LeqitAdam/EternalV1-releases (jars only, no token needed). A release's assets are named Eternal-<ver>.jar, EternalApi-<ver>.jar and eternal-web-<ver>.zip.

sudo mkdir -p /opt/eternal
cd /opt/eternal
# Download EternalApi-<ver>.jar from the latest release and save it as EternalApi.jar
VER=$(curl -s https://api.github.com/repos/LeqitAdam/EternalV1-releases/releases/latest | grep -oP '"tag_name":\s*"v\K[^"]+')
sudo curl -L -o EternalApi.jar \
  "https://github.com/LeqitAdam/EternalV1-releases/releases/download/v$VER/EternalApi-$VER.jar"

The dashboard zip (eternal-web-<ver>.zip) goes onto the web host and is unpacked there; you do not need to distribute the plugin jar by hand – the auto-updater takes care of that later via the cloud templates.

2. Create the database

Create a MySQL/MariaDB database and user. Access must only be possible from the internal network, and the password must be strong.

CREATE DATABASE eternal CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'eternal'@'127.0.0.1' IDENTIFIED BY 'EIN-STARKES-PASSWORT';
GRANT ALL PRIVILEGES ON eternal.* TO 'eternal'@'127.0.0.1';
FLUSH PRIVILEGES;

The API creates the tables itself on first start.

3. The setup wizard

On first start, the API asks in the terminal for the few things it cannot guess, generates the secrets and writes api.yml (the file gets permissions 600 and contains the DB password and secrets). Later you can run the wizard again with java -jar EternalApi.jar setup – the old file is kept as api.yml.bak.

cd /opt/eternal
sudo java -jar EternalApi.jar setup

Pressing Enter accepts the value in [brackets]. The wizard asks in German; j = yes, n = no.

1) Database

First the type (mysql/h2, default mysql). For MySQL, host (127.0.0.1), port (3306), database (eternal), user (eternal) and password follow. The wizard then tests the connection immediately:

  • ✔ Verbindung klappt. ("Connection works.") – continue.
  • ✘ Verbindung fehlgeschlagen: … ("Connection failed: …") – either correct the values (the prompt repeats) or answer Trotzdem so speichern? (j/n) ("Save anyway?") with j if, for example, the DB will only be reachable later.

2) REST API

  • Port of the API (default 7070). The dashboard only talks to it.
  • Address of the dashboard for CORS, e.g. https://dashboard.example.org. * allows all origins (only for trying things out).
  • Is the API running behind Apache/nginx? With j, it trusts the X-Forwarded-For header so the login rate limit sees the real client IP instead of the proxy IP. The default is j as soon as a concrete dashboard address was entered above.
Warning

Only trust X-Forwarded-For if the API is not directly reachable from the internet (i.e. there really is a proxy in front of it). Otherwise anyone can spoof the IP and lock others out.

3) Eternal Cloud

Answer the question „Auf diesem Rechner Services betreiben?“ ("Run services on this machine?") with j if this host should start the servers (the normal case). Then follow:

  • Name of this node (Node-1).
  • Bind address of the proxies: 0.0.0.0 = reachable from outside (port 25565 must be open), 127.0.0.1 = local only. The backend servers always bind to 127.0.0.1 and run with online-mode=false – they must never be directly reachable from the internet.
  • Address for players (domain/IP, only for display in the dashboard).
  • RAM budget for all services in MB (0 = unlimited). The wizard suggests the system memory minus 2 GB.
  • Linux user for the servers (run-as-user): only appears if the API runs as root. The suggested user minecraft must exist (sudo useradd -r -m minecraft). Empty = the servers run as root (not recommended).

Note down the secrets

At the end, the wizard shows two freshly generated values in a box:

  • the admin key (dashboard login via the „API-Key“ tab, see Dashboard accounts) – grants full access and is the bootstrap access as long as no rank has dashboard permissions yet.
  • the plugin secret (internal.shared-secret) – only needed without the cloud; then enter it in plugins/Eternal/config.yml under api.shared-secret.

Note both down once, securely. Afterwards, api.yml sits next to the jar.

4. systemd unit

To keep the API running permanently and at boot, install the included unit tools/api/eternal-api.service. It starts as root (for JDKs/low ports) and gives the node 90 s on stop to shut down all services cleanly.

sudo cp eternal-api.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now eternal-api
# Follow the logs:
journalctl -u eternal-api -f
[Unit]
Description=Eternal API + Cloud node
After=network-online.target mariadb.service mysql.service
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/eternal
ExecStart=/usr/bin/java -Xms256M -Xmx1G -jar /opt/eternal/EternalApi.jar
User=root
Restart=always
RestartSec=5
TimeoutStopSec=90
KillMode=mixed
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
Tip

If you later set updates.restart-on-update: true, the API exits by itself after a jar swap – Restart=always then starts it again. See Auto-updates.

5. Reverse proxy for the dashboard

The unpacked dashboard (eternal-web) is a static Angular app on the web host. The reverse proxy serves these files and forwards everything under /api to the Eternal API on 127.0.0.1:7070. Important: the WebSockets for the live console, the service push and the live view all run over /api/cloud/ws/* and must be passed through (upgrade headers).

To match, set server.trust-forwarded-for: true in api.yml and add the dashboard domain under cors.allowed-origins (the wizard already does this).

Apache

Enable the modules: sudo a2enmod proxy proxy_http proxy_wstunnel rewrite headers.

<VirtualHost *:443>
    ServerName dashboard.example.org
    DocumentRoot /var/www/eternal-web

    # Angular SPA: real files directly, otherwise index.html (client routing)
    <Directory /var/www/eternal-web>
        Options -Indexes
        AllowOverride None
        Require all granted
        FallbackResource /index.html
    </Directory>

    ProxyPreserveHost On
    # REST API under /api  ->  Eternal API on 127.0.0.1:7070
    ProxyPass        /api/ http://127.0.0.1:7070/
    ProxyPassReverse /api/ http://127.0.0.1:7070/

    # Pass through WebSockets (live console & service push)
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule ^/api/cloud/ws/(.*)$ ws://127.0.0.1:7070/cloud/ws/$1 [P,L]
</VirtualHost>

nginx

# Upgrade header for WebSockets
map $http_upgrade $connection_upgrade { default upgrade; '' close; }

server {
    listen 443 ssl;
    server_name dashboard.example.org;
    root /var/www/eternal-web;

    # Angular SPA
    location / { try_files $uri $uri/ /index.html; }

    # REST API + WebSockets under /api  ->  127.0.0.1:7070
    location /api/ {
        proxy_pass http://127.0.0.1:7070/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # applies to /api/cloud/ws/* (console, service push, live view)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 3600s;
    }
}

The trailing slash in ProxyPass /api/ http://127.0.0.1:7070/ or proxy_pass http://127.0.0.1:7070/; strips the /api prefix, so /api/cloud/ws/services arrives at the API as /cloud/ws/services.

Caution

The backend servers (lobby, game servers) bind to 127.0.0.1 and run with online-mode=false. If they become reachable from the internet, anyone can log in directly with any name. Only the proxy port should be exposed.

The dashboard does not update itself via the API – a separate updater runs on the web host for that. Details under Auto-updates.

6. First dashboard login

Open the dashboard in the browser (https://dashboard.example.org), choose the API-Key tab at login and enter the admin key you noted down from the wizard. This gets you in even if no rank has dashboard permissions yet.

Then set up real accounts and permissions: in-game code login, setting a password, and granting the eternal.web.* permissions via the role editor. How exactly this works is described under Dashboard accounts and Permissions.

7. Set up the cloud

Now populate Eternal Cloud – all in the dashboard under Cloud. In detail on the Eternal Cloud page; in short:

  1. Cloud → Java: install a JDK (Adoptium/Temurin, e.g. 21 or 25). Existing JDKs under /usr/lib/jvm are detected.
  2. Cloud → Versionen ("Versions"): install Paper (or Purpur/Folia/Spigot/Vanilla) and BungeeCord (or Velocity). Paper is pre-patched once; after that, a start is just copying.
  3. Cloud → Services → Erste Einrichtung ("Initial setup"): creates the tasks Proxy and Lobby, the groups Global-Proxy/Global-Server and empty templates, and starts both immediately.
  4. Distribute the plugin: the Eternal jar (cloud/Eternal.jar) is copied into every service; the auto-updater keeps it up to date (the cloud folder is automatically in plugin-dirs). For static servers or third-party CloudNet templates, add the plugin folders to updates.plugin-dirs.

8. Enter the license key

The free base (core, punishments, reports, lobby) runs immediately. For all other modules, enter the license key under Dashboard → Lizenz ("License") – it then applies network-wide. How licensing works is described under Licensing.

Next