Run as a service
Цей вміст ще не доступний вашою мовою.
An install started from a shell dies with the shell. The project ships three
systemd unit files under etc/examples/systemd/ —
onetimesecret-web.service, onetimesecret-worker.service and
onetimesecret-scheduler.service — and installing them unchanged is the
shortest correct way to keep an instance running across restarts.
They assume a finished bare-metal install, so work through Install on Linux first.
Install the units
Section titled “Install the units”sudo cp etc/examples/systemd/onetimesecret-*.service /etc/systemd/system/sudo systemctl daemon-reloadsudo systemctl enable --now onetimesecret-webThat is the whole job for most instances. enable --now both starts the
service and starts it at boot.
What the units assume
Section titled “What the units assume”Each unit runs as the user and group onetime, with WorkingDirectory set to
/var/lib/onetimesecret, and expects Valkey or Redis to be up already — the
web unit orders itself After=network.target redis-server.service valkey.service, hedging across both common service names. The worker and
scheduler additionally order themselves after onetimesecret-web.service.
The environment comes from .env in the working directory, sourced inside
ExecStart rather than through systemd’s EnvironmentFile:
ExecStart=/bin/bash -lc 'set -a; source .env; set +a; exec bundle exec puma -C etc/puma.rb'The worker and scheduler use the same form around bin/ots worker and
bin/ots scheduler.
The -l in bash -lc is load-bearing beyond .env. It is what puts a Ruby
installed for the onetime user on the service’s PATH — but only through the
files a login shell actually reads, which are /etc/profile and then the first
of ~/.bash_profile, ~/.bash_login and ~/.profile. ~/.bashrc is not among
them, so a version manager initialized there is invisible here and the unit dies
with bundle: command not found. Install on Linux writes
the rbenv line into ~/.profile for that reason; if you set Ruby up some other
way, put its initialization in one of those three files, or in an
/etc/profile.d/ snippet that /etc/profile picks up.
Setting PATH through systemd’s Environment= or EnvironmentFile= is not a
substitute. Those are applied to the process systemd starts, which here is the
login shell, and /etc/profile then runs and sets its own PATH over the top.
If the app is not at /var/lib/onetimesecret
Section titled “If the app is not at /var/lib/onetimesecret”WorkingDirectory is a literal path, not a search. An install that sits in the
onetime user’s home directory, or under /opt, will not be found, and
systemd fails the unit before Puma runs. Move the install to
/var/lib/onetimesecret rather than editing the units: it is the layout the
shipped files are written against, and it keeps all three of them correct as
delivered. If you keep the app elsewhere, change WorkingDirectory in all
three files and keep them identical — the web unit’s own header tells you to
adjust it.
ProtectHome=true is a second reason to keep the shipped layout. It makes
/home inaccessible to the service, so an install — or a version manager —
under a user’s home directory in /home stays unreachable even once
WorkingDirectory points at it. /var/lib/onetimesecret is not under /home
and is unaffected.
When you need the worker and the scheduler
Section titled “When you need the worker and the scheduler”The worker and scheduler unit headers say they are required for full
authentication mode with PostgreSQL and RabbitMQ. That is wrong in both halves,
and the real rule is simpler: background jobs are off unless you set
JOBS_ENABLED=true. While jobs are off, the web process sends email
synchronously in-process, nothing publishes work for the worker to consume, and
both extra services would sit idle. RabbitMQ matters in exactly the same case —
it is the broker the worker consumes from, and nothing needs it until jobs are
on.
Authentication mode does not decide this. Full mode adds a SQL account database, which defaults to SQLite, not a job queue; a full-mode instance with jobs off runs on the web unit alone.
JOBS_ENABLED is read from the environment, so it goes wherever the units get
their environment from: .env in the working directory, or
/etc/default/onetimesecret. Set it, then enable both units:
sudo systemctl enable --now onetimesecret-worker onetimesecret-schedulerWhile jobs are off, the health endpoint reports the job queue as
not_configured rather than as a failure, so an instance running on the web
unit alone does not look broken there.
What the units already handle
Section titled “What the units already handle”All three restart on-failure after 5 seconds, with a start limit of five
attempts per 60 seconds so a genuinely broken instance stops flapping and stays
down where you can see it. Stop timeouts differ deliberately: 30 seconds for
the web and scheduler units, 60 seconds for the worker so in-flight jobs can
drain before it is killed.
Each unit runs with NoNewPrivileges=true, ProtectSystem=strict,
ProtectHome=true and PrivateTmp=true, and declares
StateDirectory=onetimesecret/tmp onetimesecret/log. Under
ProtectSystem=strict the filesystem is read-only apart from what the unit is
granted, so any additional path the app has to write to needs granting
deliberately.
EnvironmentFile=-/etc/default/onetimesecret is present in all three units and
optional — the leading - means the service starts whether or not that file
exists. It is a second, additive source of environment variables, for values
you would rather keep outside the app directory or vary between hosts.
Without systemd
Section titled “Without systemd”Procfile.production defines the same processes for any Procfile runner —
foreman, hivemind or goreman. Only the web line is uncommented; the worker
and scheduler lines are shipped commented out. Export the environment first,
the same way the units do:
set -a; source .env; set +aforeman start -f Procfile.productionIn a container none of this applies. The main image runs a single process, and multi-process supervision is the S6 variant’s job.
Once the services are running, confirm the instance actually serves: Verify your install.