For the complete documentation index, see llms.txt. This page is also available as Markdown.

2.8 Admin Web Interface

How to configure and run the JSONAir admin web interface.

jsonair-admin is a lightweight browser-based administration tool for managing the configurations table. It provides a login-protected UI where administrators can search, create, edit, and delete configuration records without needing direct database access or the jsonair-encrypt command-line tool.

All configuration data written through the admin interface is automatically base64-encoded and encrypted using the same AES-256-GCM method that the JSONAir server uses, so agents retrieve configurations transparently with no changes on their side.


How It Works

Step
What Happens

1

Admin logs in with a username and password stored in environment variables

2

A signed JWT session cookie is issued (4-hour lifetime, HTTP-only)

3

Admin searches the configurations table by type and/or name

4

Admin opens a record — the existing config_data is decrypted and base64-decoded for display

5

Admin edits the raw configuration text and saves

6

On save, the admin interface base64-encodes the raw text, encrypts it with AES-256-GCM, and writes it back to the database

7

The JSONAir server decrypts and serves the updated configuration to agents on the next request

The admin interface shares the CONFIG_ENCRYPT_SECRET with the JSONAir server — this is what allows it to read and write encrypted config_data values that the server can then decrypt.


Building

With Make

make jsonair-admin

The binary is placed at:

Directly with Go

The HTML templates are embedded into the binary at compile time using Go's embed package. No external template files are needed at runtime — the binary is fully self-contained.


Environment Variables

Required — Admin Credentials

Variable
Description
Example

ADMIN_USERNAME

Login username for the web interface

admin

ADMIN_PASSWORD

Login password for the web interface

openssl rand -hex 16

ADMIN_SESSION_SECRET

Secret used to sign session JWTs. Use a long, random string — keep this separate from other secrets.

openssl rand -hex 32

Required — Encryption

Variable
Description

CONFIG_ENCRYPT_SECRET

Must match the value used by the JSONAir server. This is the same secret used to derive the AES-256-GCM key for config_data. If this value differs from the server's, the admin interface will not be able to decrypt existing records and the server will not be able to read records written by the admin.

Required — Database

Variable
Description
Example

MYSQL_USERNAME

Database username

jsonair

MYSQL_PASSWORD

Database password

your-db-password

MYSQL_DATABASE

Database name

jsonair

MYSQL_HOST

Database hostname or IP

127.0.0.1

MYSQL_PORT

Database port

3306

Optional — Database TLS

Variable
Description
Default

MYSQL_TLS

Set to true to enable TLS for the database connection

false

MYSQL_TLS_SKIP_VERIFY

Set to true to disable certificate verification. Not recommended for production.

false

Optional — HTTP Server

Variable
Description
Default

HTTP_LISTEN

Address and port to listen on

:8080

HTTP_TLS

Set to true to enable HTTPS

false

HTTP_CERT

Path to the TLS certificate file. Required when HTTP_TLS=true.

HTTP_KEY

Path to the TLS private key file. Required when HTTP_TLS=true.

When HTTP_TLS=true, the admin interface serves HTTPS directly. Alternatively, leave TLS disabled and terminate it at a reverse proxy (nginx, Caddy, etc.).


Example .env File

Security: Never commit a .env file containing real credentials to source control. Add .env to your .gitignore.


Running the Admin Interface

Directly

Place a .env file in the same directory as the binary and run:

As a systemd Service

Create /etc/systemd/system/jsonair-admin.service:

Place your environment variables in /etc/jsonair/admin.env, then enable and start the service:

With HTTPS

Set the three TLS variables and the admin interface will serve HTTPS directly — no reverse proxy required.

When TLS is enabled the server enforces TLS 1.2 as the minimum version, adds a Strict-Transport-Security header to every response, and marks the session cookie Secure so it is never transmitted over plain HTTP.

Tip: Generate a self-signed certificate for internal use: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=jsonair-admin'

In a Container

Because all configuration is passed via environment variables and the binary is fully self-contained, the admin interface is straightforward to run in a container. A minimal Dockerfile looks like:

Or using a minimal base image:

Pass environment variables at runtime:

Note: Cross-compile for Linux when building on macOS: GOOS=linux GOARCH=amd64 go build -o jsonair-admin ./cmd/jsonair-admin


Health Check

jsonair-admin exposes an unauthenticated health endpoint at /health. It pings the database and returns HTTP 200 when healthy or HTTP 503 when the database is unreachable.

Healthy response:

Unhealthy response (HTTP 503):

Docker HEALTHCHECK

Replace 8080 with the port set in HTTP_LISTEN if you change the default.


Usage

Logging In

Navigate to http://your-host:8080 (or https:// if HTTP_TLS=true) using the address set in HTTP_LISTEN. You will be redirected to the login page. Enter the ADMIN_USERNAME and ADMIN_PASSWORD values from your environment.

Sessions expire after 4 hours of inactivity. You will be redirected to the login page when your session expires.

Searching Configurations

After login you land on the Configurations list page. All records from the configurations table are shown in a table with columns for Key UUID, Type, Name, Reload, Debug, and last-updated timestamp.

Use the Type and Name search fields at the top to filter the list. Filters are substring matches, so searching for suri in the Type field will match suricata. Both filters can be combined. Click Clear to reset.

Creating a Configuration

Click + New Configuration to open the creation form. Fill in the following fields:

Field
Description

Key (UUID)

The key UUID this configuration belongs to. Select from the dropdown — it lists all records in the keys table. The agent must authenticate with this key to retrieve the configuration.

Type

The configuration type (e.g. suricata, nginx). Must match what the agent sends in its JSONAIR_TYPE variable.

Name

The configuration name (e.g. suricata.yaml). Must match what the agent sends in its JSONAIR_NAME variable.

Reload

Optional reload key or trigger value.

Debug

Optional debug level (e.g. INFO, DEBUG).

Configuration Data

Paste the raw configuration text here. Any format is accepted — YAML, JSON, TOML, plain text, binary, etc. The admin interface does not validate the content.

Click Create to save. The raw text is base64-encoded and encrypted before being written to the database.

Editing a Configuration

Click Edit next to any record in the list. The edit form shows the same fields as the creation form, pre-populated with the current values. The Configuration Data textarea displays the decrypted, decoded raw configuration text.

Make any changes and click Save. The updated text will be re-encoded and re-encrypted.

Note: Changing the Type or Name of a configuration will break any agents currently polling for the old type/name combination. Update agents before changing these fields in production.

Deleting a Configuration

Click Delete next to any record in the list. A browser confirmation dialog will appear before the record is permanently removed. Deletion cannot be undone.


Security Considerations

  • Keep the admin interface off the public internet. Run it on an internal network, behind a VPN, or behind an authenticated reverse proxy. It provides direct read and write access to all configuration data in the database.

  • The session cookie is HTTP-only and SameSite=Strict to mitigate XSS and CSRF attacks. When HTTP_TLS=true, the cookie is also marked Secure so it is never transmitted over plain HTTP. Either enable TLS directly or place the admin interface behind a TLS-terminating reverse proxy (nginx, Caddy, etc.) when running over an untrusted network.

  • ADMIN_SESSION_SECRET, ADMIN_PASSWORD, and CONFIG_ENCRYPT_SECRET should each be distinct values generated with openssl rand -hex 32.

  • The admin interface does not drop OS privileges at startup (unlike the main server). Run it as a dedicated low-privilege user.

Last updated