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
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-adminThe 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
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
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
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
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
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
.env FileSecurity: Never commit a
.envfile containing real credentials to source control. Add.envto 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:
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/namecombination. 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, andCONFIG_ENCRYPT_SECRETshould each be distinct values generated withopenssl 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