From b063a0d71a4832c80eedd131f476150ebbc25af9 Mon Sep 17 00:00:00 2001 From: Jason Wright Date: Mon, 6 Jul 2026 14:18:55 -0600 Subject: [PATCH] docs(production): document service-management permissions Fix typos and clarify the production runbook. Document how the redux group is granted NOPASSWD sudo for start/stop/restart and for `docker compose pull`, and correct the restart/update flows to match. Co-Authored-By: Claude Opus 4.8 --- Documentation/production.md | 182 ++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 92 deletions(-) diff --git a/Documentation/production.md b/Documentation/production.md index bc24219a..4fb76ced 100644 --- a/Documentation/production.md +++ b/Documentation/production.md @@ -2,127 +2,125 @@ Running redux on the production server is documented here. -## Initial configuration +## Common operations -We're going to assume the system is using systemd (the current -system process manager used by almost all Linux distributions). +### How to restart the services -First, install the systemd service file. The file below should -be installed to `/etc/systemd/system/redux.service`, owned by root/root and -not writeable by anyone else. +All of the services are run as a single docker composition and it is +started and stopped via systemd. Members of the `redux` group are granted +permission to start/stop/restart the service via sudo (see +[How it is configured](#how-it-is-configured) below), so no password is +required. +To start/restart: +``` +sudo systemctl restart redux ``` -[Unit] -Description=redux -Documentation=Redux backend -After=network-online.target -After=remote-fs.target -Wants=network-online.target -Wants=remote-fs.target -ConditionPathExists=/home/USER/Redux -[Service] -Type=simple -User=USER -ExecStart=/home/USER/.dotnet/dotnet run -WorkingDirectory=/home/USER/Redux -ExecReload=/bin/kill $MAINPID -Restart=on-failure +To stop: +``` +sudo systemctl stop redux +``` -[Install] -WantedBy=multi-user.target +If you want to disable the service (or re-enable it), systemctl's +enable/disable commands can be used. Note that the sudo grant only +covers start/stop/restart; enable/disable require a password. -# -# There are a few variables you might want to edit: -# - ExecStart -# - WorkingDirectory -# - User -# - ConditionPathExists -# -# ExecStart should be the location of the dotnet command -# which can be found by doing "which dotnet". It should be -# followed by the "run" command -# -# WorkingDirectory is the location of the API.csproj file -# for Redux (the base directory for the repository) -# -# User is the username of the user whose permissions should be -# used to run the backend. -# -# ConditionPathExists should be the same as WorkingDirectory -# (if you delete the directory, this service will not try to start) -``` +### Viewing the logs -To ensure the file ownership and mode: +systemd services use journalctl to manage their logs. To view, use the command below. +Note that this log has entries for all of the redux services. ``` -chown root:root /etc/systemd/system/redux.service -chmod 644 /etc/systemd/system/redux.service +sudo journalctl -xeu redux ``` +### Updating + +The docker containers are NOT upgraded regularly and must be manually upgraded on +the production machine (portneuf). They are regularly updated on `redux.thought.net`, +though. -Make sure you kill off any currently running Redux server, and then -let's get systemd to do the rest of the work: +To update the packages on the production server: ``` -# systemd will notice/read the new service file -systemctl daemon-reload -# systemd will start the service on boot -systemctl enable redux.service -# go ahead and start it now -systemctl start redux.service +$ sudo docker compose pull +[+] Pulling 4/4 + ✔ redux-gui Pulled 0.8s + ✔ mcpredux Pulled 0.8s + ✔ redux Pulled 0.9s + ✔ quantumsolver Pulled 0.8s +$ sudo systemctl restart redux ``` -That's it to get things into normal operation! +The restart completes without a password prompt because the sudoers rule +grants the `redux` group NOPASSWD access to manage the service. -## What about updates? +## How it is configured -From time to time, you'll want to update the code base and -restart the service. +All of the redux services (Redux_GUI, Redux, mcpredux, quantumsolver) are +composed into a set of docker containers. Each container is built by github actions +and the composition file uses those containers. There is no source code on the +production server. -``` -# get to the right directory -cd [working directory with API.csproj in it] +The compose file can be found in `/home/redux/docker-compose.yml`. It currently +exposes the following ports to the internet at large: + - Redux (http on 27000) + - Redux_GUI (http on 3000) + - mcpredux (http on 27200) + - quantumsolver (http on 27100) -# pull changes into working directory -git pull origin + Internally, Redux_GUI and mcpredux connect to Redux on the docker private network. + Likewise, Redux connects to quantumsolver on the docker private network. The public + exposure of the other ports is a legacy behavior. -# restart the service -sudo systemctl restart redux.service -``` +In front of the composed container is an nginx server which handles TLS and connects +to redux as a reverse proxy. -## What about errors? + ### service restarts (sudo) -Errors logged via `Console.WriteLine` are sent to the standard output -of dotnet programs. Luckily, systemd logs these in a circular buffer -by default. To view it: + Members of the `redux` group are allowed to start/stop/restart the service + without a password via the following line in /etc/sudoers (edit with + `visudo`): -``` -# show the console log for redux -journalctl -xeu redux -``` + ``` + %redux ALL=(root) NOPASSWD: /usr/bin/systemctl restart redux, \ + /usr/bin/systemctl stop redux, \ + /usr/bin/systemctl start redux + ``` -## Stop the service + This covers start/stop/restart only; enabling/disabling the unit is not + granted and still prompts for a password. The command match is exact, so + only these three invocations (no extra arguments) are permitted. -If you want to stop the service, easy enough: + ### docker container updates -``` -sudo systemctl stop redux.service -``` + This requires the following line in /etc/sudoers: -Stopping it stops it for now. It will still restart on boot. To -disable it (make sure it never starts again): + ``` + %redux ALL=(root) CWD=/home/redux NOPASSWD: /usr/bin/docker compose pull + ``` -``` -sudo systemctl disable redux.service -``` +### systemd + +The service file can be found in `/etc/systemd/system/redux.service` and +looks something like: -## Why use systemd? +``` +[Unit] +Description=Redux composition +After=docker.service +Requires=docker.service -Running services as root is dangerous. If there's a vulnerability, the -attacker can run code as the user running the process. Using an -unpriviledged user means that the potential damage from a vulnerability -is limited drastically. +[Service] +Type=simple +User=redux +Group=redux +WorkingDirectory=/home/redux +ExecStart=docker compose up +ExecStop=docker compose down +Restart=on-failure +RestartSec=5 -Further, we get logging infrastructure for free: systemd logs the -standard output in such a way that we don't have to worry about filling -the disk on really bad looping errors, etc. +[Install] +WantedBy=multi-user.target +```