Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
COMMON_OVERLAYS += $(CURDIR)/overlay

include $(FAB_PATH)/common/mk/turnkey/nodejs-tklwebcp.mk
include $(FAB_PATH)/common/mk/turnkey.mk
62 changes: 33 additions & 29 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
Redis - Open Source, In-memory Data Structure Store
===================================================

`Redis`_ can be used as a database, cache or message broker. It supports data
structures such as strings, hashes, lists, sets, sorted sets
with range queries, bitmaps, hyperloglogs and geospatial indexes
with radius queries. Redis has built-in replication, Lua scripting,
LRU eviction, transactions and different levels of on-disk persistence,
and provides high availability via `Redis Sentinel`_ (requires install of
Debian `redis-sentinel`_ package) and automatic partitioning with
`Redis Cluster`_.
`Redis`_ is an in-memory database, cache and message broker. It supports
strings, hashes, lists, sets, sorted sets, streams and other data structures.
Redis also provides replication, scripting, transactions, on-disk persistence,
high availability through `Redis Sentinel`_ and partitioning through
`Redis Cluster`_. Sentinel requires the optional Debian `redis-sentinel`_
package.

This appliance includes all the standard features in `TurnKey Core`_,
and on top of that:

- Redis configurations:
- Redis configuration:

- Installed from debian package repository (auto security updates).
- Includes web based management tool `Redis Commander`_.
- Complex Redis system password auto-generated on firstboot (security).
- Confconsole plugin provided to view Redis system password (convenience).
- Redis Server and its command-line tools come from Debian Trixie and use
normal APT security updates.
- First boot generates a strong Redis password. View it from Confconsole or
run ``turnkey-redis-pw get`` as root.
- First boot lets you keep Redis on localhost, bind all interfaces or enter
a local address. Remote deployments should restrict TCP port 6379 to
trusted clients with the firewall.
- Debian's default RDB persistence remains enabled.

**Security note**: Updates to `Redis Commander`_ may require supervision so
they **ARE NOT** configured to install automatically. See `Plone
documentation`_ for upgrading.
- Includes the `Redis Commander`_ browser interface at
``https://<appliance>/redis-commander/``.

- SSL support out of the box.
- HTTPS protects the landing page and Redis Commander management interface.
- Postfix MTA (bound to localhost) to allow sending of email from web
applications (e.g., password recovery).
applications.

Supervised Manual Redis Commander Update
----------------------------------------
Supervised Redis Commander update
---------------------------------

Always ensure that you have a current and tested backup before performing an
upgrade. Ideally also do a test upgrade proceedure on a development server,
before updating your production server.::
upgrade. Test the update on a development server before updating production.::

su - node -c "cd /opt/tklweb-cp && npm update"
su - node -c "cd /opt/tklweb-cp && npm install redis-commander@latest"
systemctl restart pm2-node

The npm lock file records registry integrity hashes. Redis Server itself is
updated through APT.

Credentials *(passwords set at first boot)*
-------------------------------------------

- Webmin, SSH: username **root**
- Redis-commander: username **admin**
- Redis Commander: username **admin**

.. _Redis: https://redis.io/
.. _Redis Sentinel: https://redis.io/topics/sentinel
.. _redis-sentinel: https://packages.debian.org/stretch/redis-sentinel
.. _Redis Cluster: https://redis.io/topics/cluster-tutorial
.. _Redis: https://redis.io/docs/latest/
.. _Redis Sentinel: https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/
.. _redis-sentinel: https://packages.debian.org/trixie/redis-sentinel
.. _Redis Cluster: https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/
.. _TurnKey Core: https://www.turnkeylinux.org/core
.. _Redis Commander: https://joeferner.github.io/redis-commander/
.. _Redis Commander: https://github.com/joeferner/redis-commander
22 changes: 22 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
turnkey-redis-19.0 (1) turnkey; urgency=low

* Upgrade the base distribution to Debian 13/Trixie.

* Update Redis to Debian's 8.0 series.

* Use Debian's Node.js and npm packages for the management application
runtime.

* Install Redis Commander from its maintained npm registry release with
dependency integrity metadata and a supported npm update path.

* Preserve the selected Redis network binding and reliably reload the
first-boot Redis Commander credentials.

* Start Nginx after first-boot TLS certificate generation so Redis Commander
is available on the initial HTTPS session.

* See the TurnKey Core 19.0 changelog for changes common to all appliances.

-- TurnKey Linux release engineering <release@turnkeylinux.org> Mon, 24 Aug 2026 00:00:00 +0000

turnkey-redis-18.0 (1) turnkey; urgency=low

* Update Redis-Commander (via NPM) to latest upstream release: v0.8.1.
Expand Down
35 changes: 29 additions & 6 deletions conf.d/main
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
#!/bin/bash -ex

NODEUSER=node
NODEAPP=/opt/tklweb-cp

REPO="joeferner/redis-commander"
VERSION=$(gh_releases $REPO | sort -V | tail -1)
URL="git+https://github.com/$REPO.git"
# Keep npm registry access on the system-managed trust path.
grep -qxF 'cafile=/etc/ssl/certs/ca-certificates.crt' /home/$NODEUSER/.npmrc || \
echo 'cafile=/etc/ssl/certs/ca-certificates.crt' >> /home/$NODEUSER/.npmrc
chown $NODEUSER:$NODEUSER /home/$NODEUSER/.npmrc

su -lc "[[ "$FAB_HTTP_PROXY" ]] && export http_proxy=$FAB_HTTP_PROXY; cd /opt/tklweb-cp && npm i $URL#$VERSION" $NODEUSER
su -lc "[[ "$FAB_HTTP_PROXY" ]] && export http_proxy=$FAB_HTTP_PROXY; cd /opt/tklweb-cp && pm2 start ecosystem.config.js && sleep 20 && pm2 save && pm2 kill" $NODEUSER
# Redis Commander is not packaged by Debian. Install the current release from
# its maintained npm channel and retain npm's integrity-bearing lock file.
VERSION=$(su -lc "npm view redis-commander version" $NODEUSER)
su -lc "[[ -n \"$FAB_HTTP_PROXY\" ]] && export http_proxy=\"$FAB_HTTP_PROXY\"; cd $NODEAPP && npm install --save-exact redis-commander@$VERSION" $NODEUSER
su -lc "cd $NODEAPP && pm2 start ecosystem.config.js && sleep 20 && pm2 save && pm2 kill" $NODEUSER

echo {} > /opt/tklweb-cp/node_modules/redis-commander/config/local-production.json
echo {} > $NODEAPP/node_modules/redis-commander/config/local-production.json

rm /etc/nginx/sites-enabled/tkl-default
ln -s /etc/nginx/sites-available/redis /etc/nginx/sites-enabled/redis

# The inherited build profile uses n temporarily. Ship Debian's maintained
# Trixie Node.js and npm commands while retaining the npm-managed PM2 service.
rm -f /usr/local/bin/{n,node,npm,npx,corepack}
rm -rf /usr/local/n \
/usr/local/src/n \
/usr/local/include/node \
/usr/local/lib/node_modules/npm \
/usr/local/lib/node_modules/corepack \
/usr/local/share/doc/node \
/usr/local/share/man/man1/node.1
rm -f /usr/local/etc/npmrc

hash -r
dpkg-query -S "$(readlink -f "$(command -v node)")" | grep -q '^nodejs:'
dpkg-query -S "$(readlink -f "$(command -v npm)")" | grep -q '^npm:'

rm -rf /tmp/npm*
111 changes: 111 additions & 0 deletions docs/v19.0-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Redis 19.0 testing

## Scope and source decision

Redis 19.0 uses Debian 13 Trixie packages for Redis Server, Redis command-line
tools, Node.js, npm and Nginx. Redis Commander is not packaged by Debian, so it
comes from the project's maintained npm registry channel. npm records registry
integrity hashes in `/opt/tklweb-cp/package-lock.json` and provides the
documented `npm install redis-commander@latest` update path.

The inherited Node.js build profile temporarily uses the `n` version manager
while assembling the management application. Product configuration removes
that runtime and version manager so the shipped `node` and `npm` commands are
owned by Debian packages. The `node` account uses the system CA bundle for npm
registry access.

## Acceptance command

```sh
/sandboxed-git/turnkey/tools/test-v19-appliance redis \
--source /home/agent/.local/worktrees/turnkey-apps/redis/wish-redis-v19-trixie
```

The command builds a Trixie root filesystem, imports it into Docker, boots the
normal systemd and firstboot path, then runs `tests/v19.sh`. The retained
harness report records the exact source and harness revisions, archive and tree
hashes, installed versions, configured-root mode, runtime evidence, updater
evidence, cleanup result and verdict.

Acceptance passed in run `20260824t112332z-4695-11523` with source
`aec0174d7f59a124757989bb5871af11f0ce4d08` and harness
`b6f8b8c2f3e8f00fd5cf36869e645fc08f01f87e`. The report is retained at
`/home/agent/.local/state/turnkey-v19-harness/runs/redis/20260824t112332z-4695-11523/report.txt`.
Its source archive SHA-256 is
`3f29578766f012c27c8d767ee2d118e1192e49398114924fc38029e6f12c567e`,
input tree SHA-256 is
`55b2f18dbdb5a9c5680926ebcb97513c306ecf7be2bd54c4d8f33b6043c44537`
and build tree SHA-256 is
`b6fd2e7d6f4696e81cf6ebd23f4fe14104784899d2c687dc982993a7327ac061`.
Build, import, normal boot, product tests and cleanup passed. The command
`sha256sum -c SHA256SUMS` passed for all eight retained report artifacts.

The accepted image contained Redis Server and tools
`5:8.0.2-3+deb13u2`, Node.js `20.19.2+dfsg-1+deb13u2`, npm
`9.2.0~ds1-3`, Nginx `1.26.3-3+deb13u7` and Redis Commander `0.9.0`.

## README crosswalk

| README contract | Focused check | Required result | Evidence |
| --- | --- | --- | --- |
| Redis Server and tools come from Debian Trixie | Resolve dpkg versions, refresh APT and inspect candidates | Installed packages retain eligible signed Trixie candidates | `tests/v19.sh`; harness updater fields |
| First boot generates an authenticated Redis service | Retrieve the generated password, reject an unauthenticated PING and perform an authenticated PING | Unauthenticated access is denied and authenticated access returns `PONG` | `tests/v19.sh`; harness runtime fields |
| The selected all-interface binding and protected mode are applied | Inspect the live firstboot-generated Redis configuration | `bind 0.0.0.0`, `protected-mode yes` and the generated password are present | `tests/v19.sh` |
| Redis stores, retrieves, persists and deletes data | Set a disposable key, run synchronous `SAVE`, restart Redis, retrieve the value, delete it and prove it is absent | The complete database round trip passes across a service restart | `tests/v19.sh`; harness runtime fields |
| Redis Commander is available through authenticated HTTPS | Load the login page, prove the connections API rejects an anonymous request, sign in with the firstboot administrator credential and query that API with its bearer token | The login page loads, anonymous API access returns 401 and the authenticated API reports the configured Redis connection | `tests/v19.sh` |
| The landing page links Redis Commander and Webmin | Request the HTTPS landing page | Redis GUI and Webmin links are present | `tests/v19.sh` |
| PM2 supervises Redis Commander and the TurnKey control panel | Inspect PM2 JSON state after normal boot | Both processes are online with live PIDs | `tests/v19.sh` |
| Redis Commander has integrity and a maintained update path | Inspect the npm lock, query the registry candidate and exercise an older-to-current update in a disposable Trixie fixture | Registry integrity hashes are present and the interface works before and after update | `tests/v19.sh`; `tests/v19-upgrade.sh` |
| Postfix, Webmin and root SSH are inherited Core behavior | Cite the unchanged Core layer | Core 19 baseline passes | Core run `20260824t010251z-1634-32241`, source `24c82ee3540ce545422742b0e28ba6b687c53ec2`, verdict `PASS` |

## Updater checks

`tests/v19.sh` runs `apt-get update`, confirms eligible Trixie candidates for
`redis-server`, `redis-tools`, `nodejs`, `npm` and `nginx`, and verifies the
installed versions remain unchanged. It queries the current Redis Commander
candidate from npm without changing the accepted appliance. The documented
supervised update command is:

```sh
su - node -c "cd /opt/tklweb-cp && npm install redis-commander@latest"
systemctl restart pm2-node
```

`tests/v19-upgrade.sh` is a disposable Trixie fixture. It installs Redis
Commander 0.8.0, verifies its legacy authenticated page, updates through the
official npm channel, restarts Commander, signs in through the current form
and bearer-token flow, queries the protected connections API and proves the
Redis value survived. It also checks the current version and lock-file
integrity fields.

The fixture was run with the application source and local Docker inspection CA
mounted read-only:

```sh
docker run --rm --name tkl-redis-v19-upgrade-loop3 \
--mount type=bind,src=/home/agent/.local/worktrees/turnkey-apps/redis/wish-redis-v19-trixie,dst=/src,readonly \
--mount type=bind,src=/usr/local/share/ca-certificates/microsandbox-ca.crt,dst=/usr/local/share/ca-certificates/microsandbox-ca.crt,readonly \
debian:trixie-slim /src/tests/v19-upgrade.sh
```

It upgraded Redis Commander from 0.8.0 to 0.9.0, matched the 0.9.0 registry
candidate, served the authenticated interface before and after the update and
preserved the fixture Redis value. The initial run without the local Docker CA
failed at registry TLS verification before installation. A second assumption
check found that v0.8.1 was released only as a Git tag, not an npm version, so
the fixture uses the published 0.8.0 registry release as its baseline.

## Known limitation

Docker runtime validation does not exercise the installer, kernel, bootloader
or physical hardware. Redis adds no appliance-specific behavior at those
boundaries, so the validated Core 19 baseline supplies inherited evidence.

## Deferred issues

The current official Redis Commander dependency tree emits deprecation notices
and an npm audit summary of one low, two moderate, three high and one critical
finding. These are upstream transitive-dependency findings rather than a
failure in the documented flow. Force-updating transitive packages outside the
maintained Redis Commander release is deferred for release review because it
could break the supported update path.
39 changes: 20 additions & 19 deletions overlay/usr/lib/inithooks/bin/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ def main():
("local", "Enter custom range")))
if bind == "all":
bind_ip = "0.0.0.0"
if bind == "local":
elif bind == "local":
localaddr = InterfaceInfo(get_ifnames()[0]).address
d = Dialog('TurnKey Linux - First boot configuration')
bind_ip = d.get_input("Bind IP Range", "Enter bind ip range", localaddr)
bind_ip = d.get_input("Bind IP Range", "Enter bind ip range", localaddr)
else:
bind_ip = "127.0.0.1"

Expand Down Expand Up @@ -102,26 +102,27 @@ def main():
redis_commander_conf])

# restart redis and redis commander if running so change takes effect
try:
subprocess.run(["systemctl", "is-active",
"--quiet", "redis-server.service"])
subprocess.run(["service", "redis-server", "restart"])
except ExecError:
pass
if subprocess.run(["systemctl", "is-active", "--quiet",
"redis-server.service"]).returncode == 0:
subprocess.run(["service", "redis-server", "restart"], check=True)

# reload and restart pm2 so changes take affect
# and save them to /home/node/.pm2/dump.pm2
try:
subprocess.run(["systemctl", "is-active",
"--quiet", "pm2-node.service"])
subprocess.run(["systemctl", "reload",
"pm2-node.service"])
# subprocess.run(["rm", "/home/node/.pm2/dump.pm2"])
subprocess.run(["pm2", "reload", "/opt/tklweb-cp/ecosystem.config.js"],env={"PM2_HOME": "/home/node/.pm2", "PATH": "/usr/local/bin"}, check=True, user="node")
subprocess.run(["pm2", "save"],env={"PM2_HOME": "/home/node/.pm2", "PATH": "/usr/local/bin"}, check=True, user="node")
subprocess.run(["service", "pm2-node", "restart"])
except ExecError:
pass
if subprocess.run(["systemctl", "is-active", "--quiet",
"pm2-node.service"]).returncode == 0:
environment = [
"env", "PM2_HOME=/home/node/.pm2",
"PATH=/usr/local/bin:/usr/bin:/bin",
]
subprocess.run([
"runuser", "--user", "node", "--", *environment,
"pm2", "reload", "/opt/tklweb-cp/ecosystem.config.js",
], check=True)
subprocess.run([
"runuser", "--user", "node", "--", *environment,
"pm2", "save",
], check=True)
subprocess.run(["service", "pm2-node", "restart"], check=True)


if __name__ == "__main__":
Expand Down
4 changes: 4 additions & 0 deletions overlay/usr/lib/inithooks/firstboot.d/40redis
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ fi

$INITHOOKS_PATH/bin/redis.py --pass="$APP_PASS" \
--bind="$APP_IP_BIND" --protected_mode="$APP_PROTECTED"

# The TLS certificate hook only restarts services that were already active.
# Ensure Nginx starts with the completed certificate and key pair.
systemctl restart --quiet nginx.service
1 change: 1 addition & 0 deletions overlay/usr/local/etc/npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cafile=/etc/ssl/certs/ca-certificates.crt
3 changes: 3 additions & 0 deletions plan/main
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
#include <turnkey/nodejs-nginx>

redis-server
redis-tools
nodejs # Debian Node.js runtime
npm # Debian Node.js package manager
Loading