11
31
Fork
You've already forked silverfish
19

Add template silverfish.service as a user service #166

Merged
sabrinagannon merged 21 commits from 162-systemd-service into main 2025年12月11日 01:57:18 +01:00

Close #162 by adding a silverfish.service user service file.

I put it in the project root for now because there was no obvious-to-me better alternative; open to suggestions.
Steps to install assuming a download and compilation of the code directly are commented, but are there other plans for how the binary might be distributed?
I wasn't sure how best to package it altogether.

Close https://codeberg.org/conjured/silverfish/issues/162 by adding a `silverfish.service` user service file. I put it in the project root for now because there was no obvious-to-me better alternative; open to suggestions. Steps to install assuming a download and compilation of the code directly are commented, but are there other plans for how the binary might be distributed? I wasn't sure how best to package it altogether.
Add template silverfish.service as a user service
All checks were successful
CI Silverfish Stall / silverfish-stall-amd64 (pull_request) Successful in 3m43s
558c3923eb
sabrinagannon changed title from (削除) Add template silverfish.service as a user service (削除ここまで) to WIP: Add template silverfish.service as a user service 2025年11月29日 00:25:30 +01:00
sabrinagannon changed title from (削除) WIP: Add template silverfish.service as a user service (削除ここまで) to Add template silverfish.service as a user service 2025年11月29日 00:25:47 +01:00
zkat left a comment
Copy link

putting this in the root for now seems fine (like the flakes) and I don't think we need to worry about packaging stuff just yet (that would be the distro packagers' jobs. We're mostly just helping make their jobs easier here, and they'll all almost certainly edit this file themselves for distro-specific needs).

putting this in the root for now seems fine (like the flakes) and I don't think we need to worry about packaging stuff just yet (that would be the distro packagers' jobs. We're mostly just helping make their jobs easier here, and they'll all almost certainly edit this file themselves for distro-specific needs).
@ -0,0 +1,16 @@
# Service file template for silverfish.
# To use:
# 1. copy this file to /etc/systemd/user
# 2. copy the silverfish binary to /usr/local/bin
Owner
Copy link

this says /usr/local/bin but the [Service] below says /usr/bin/silverfish

this says `/usr/local/bin` but the `[Service]` below says `/usr/bin/silverfish`
sabrinagannon marked this conversation as resolved
@ -0,0 +10,4 @@
[Service]
Type=simple
ExecStart=/usr/bin/silverfish
Restart=on-failure
Owner
Copy link

Can we maybe do something a bit fancier with maybe https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#StartLimitIntervalSec=interval &co, so the service stop restarting if it fails repeatedly in a time window, then pauses trying to restart for a while, then resumes trying to restart? I don't know what kind of stuff systemd can do here, but I think at least limiting restarts a bit would be good to do so folks don't get into error restart loops.

Can we maybe do something a bit fancier with maybe https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#StartLimitIntervalSec=interval &co, so the service stop restarting if it fails repeatedly in a time window, then pauses trying to restart for a while, then resumes trying to restart? I don't know what kind of stuff systemd can do here, but I think at least limiting restarts a bit would be good to do so folks don't get into error restart loops.
Owner
Copy link

also tagging in @cjdesno and @doctor_yiff who do Seeing Eye-flavored stuff like this for their comments/ideas.

also tagging in @cjdesno and @doctor_yiff who do Seeing Eye-flavored stuff like this for their comments/ideas.
Contributor
Copy link

Wondering if @magnet_powered knows about adding a service to the nix flake

This seems to be the best post I can find about it https://blog.lenny.ninja/posts/2023-04-16-packaging-nix-services-2.html

Wondering if @magnet_powered knows about adding a service to the nix flake This seems to be the best post I can find about it https://blog.lenny.ninja/posts/2023-04-16-packaging-nix-services-2.html
Contributor
Copy link

Some things:

  1. It should probably use dynamic users so it doesn't run as root.
  2. You should set NoNewPrivileges and ProtectHome and maybe look at systemd-analyze security for other security options you should set.
  3. The Type should be exec not simple as the systemd docs say; this is almost always the correct choice.
  4. You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory).
Some things: 1. It should probably use dynamic users so it doesn't run as root. 2. You should set `NoNewPrivileges` and `ProtectHome` and maybe look at `systemd-analyze security` for other security options you should set. 3. The `Type` should be `exec` not `simple` as the systemd docs say; this is almost always the correct choice. 4. You should set the `RuntimeDirectory`, `CacheDirectory`, `StateDirectory` and `LogsDirectory` to `silverfish`, so that systemd creates these directories for you in the allropriate place (e.g. `/var/lib/silverfish` for the state directory).
Owner
Copy link

@jalil re: 4, that will also involve making sure silverfish is configured to use those directories, yes? We currently have configurations for tmp, uploads, db, and themes

@jalil re: 4, that will also involve making sure silverfish is configured to use those directories, yes? We currently have configurations for tmp, uploads, db, and themes
Contributor
Copy link

@zkat wrote in #166 (comment):

@jalil re: 4, that will also involve making sure silverfish is configured to use those directories, yes? We currently have configurations for tmp, uploads, db, and themes

Yes, they are exported as variables though, no need to hard code them: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#RuntimeDirectory=

@zkat wrote in https://codeberg.org/conjured/silverfish/pulls/166#issuecomment-8588172: > @jalil re: 4, that will also involve making sure silverfish is configured to use those directories, yes? We currently have configurations for tmp, uploads, db, and themes Yes, they are exported as variables though, no need to hard code them: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#RuntimeDirectory=
Owner
Copy link

Ahhh. We don't look for those variables, so we'll still have to pass them in as part of the command line (or set new environment variables that silverfish DOES understand).

Like:

ExecStart=/usr/local/bin/silverfish serve --tmp-dir $TMP --themes-dir "$STATE_DIR/themes" ...etc

I wonder if this means we should use silverfish's --config-dir facilities (which work a bit different from the standalone config, as it's config-env-aware (prod/dev/etc).

Ahhh. We don't look for those variables, so we'll still have to pass them in as part of the command line (or set new environment variables that silverfish DOES understand). Like: ``` ExecStart=/usr/local/bin/silverfish serve --tmp-dir $TMP --themes-dir "$STATE_DIR/themes" ...etc ``` I wonder if this means we should use silverfish's `--config-dir` facilities (which work a bit different from the standalone config, as it's config-env-aware (prod/dev/etc).
Contributor
Copy link

You could set environment variables in the service directly:

[Service]
Environment=SILVERFISH_THEMES_DIR=%S/themes
Environment=SILVERFISH_TMP_DIR=%T

See here for the systemd specifiers you can use inside .service files.

You could set environment variables in the service directly: ```service [Service] Environment=SILVERFISH_THEMES_DIR=%S/themes Environment=SILVERFISH_TMP_DIR=%T ``` See [here](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#Specifiers) for the systemd **specifiers** you can use inside `.service` files.
Contributor
Copy link

@PolarSilliness wrote in #166 (comment):

Wondering if @magnet_powered knows about adding a service to the nix flake

This seems to be the best post I can find about it https://blog.lenny.ninja/posts/2023-04-16-packaging-nix-services-2.html

I did look into this a while ago, but it was around when silverfish became the "main" repo, and I think some things got moved around and I got a little confused, so I gave up.

In addition to the blog post you've mentioned, I'm also aware of nix-foundryvtt, a repo that builds a rust binary and declares a systemd service for it all in nix, which would make for a good reference example.

If we want a nix-defined service, I think it would be easiest to get a basic non-nix service description working first, iterate on it until it's at a point that it does the things we want it to, then make a nix version of it. Whatever is decided, I'd be happy to answer questions on nix things :)

@PolarSilliness wrote in https://codeberg.org/conjured/silverfish/pulls/166#issuecomment-8576070: > Wondering if @magnet_powered knows about adding a service to the nix flake > > This seems to be the best post I can find about it https://blog.lenny.ninja/posts/2023-04-16-packaging-nix-services-2.html I did look into this a while ago, but it was around when silverfish became the "main" repo, and I think some things got moved around and I got a little confused, so I gave up. In addition to the blog post you've mentioned, I'm also aware of [nix-foundryvtt](https://github.com/reckenrode/nix-foundryvtt), a repo that builds a rust binary and declares a systemd service for it all in nix, which would make for a good reference example. If we want a nix-defined service, I think it would be easiest to get a basic non-nix service description working first, iterate on it until it's at a point that it does the things we want it to, then make a nix version of it. Whatever is decided, I'd be happy to answer questions on nix things :)
silverfish.service: env vars and start limits
All checks were successful
CI Silverfish Stall / silverfish-stall-amd64 (pull_request) Successful in 3m41s
ca1973892a
- fix type of service to be "exec"
- correct paths for where to store executable and where to put service
 unit file
- Set environment variables for paths needed by silverfish, pass those
 into ExecStart
Security improvements:
- Set DynamicUSer, ProtectHome to 'yes'
- Set NoNewPrivileges to 'true'
- WorkingDirectory and RootDirectory are set.
Restart behaviour:
- Adds a start limit to no more than 3 restart attempts within 120s
- Note: does NOT have behaviour to recover from when start limits have
 been exceeded, will need to decide on how we want to handle that.
sabrinagannon left a comment
Copy link

@jalil & @zkat - this commit attempts to address some of your comments. The security is still not where I'd like it to be but I'm a little out of my depth on some of the other options and wanted to push up what I had with annotations.

@jalil & @zkat - this commit attempts to address some of your comments. The security is still not where I'd like it to be but I'm a little out of my depth on some of the other options and wanted to push up what I had with annotations.
@ -0,0 +15,4 @@
Environment=SILVERFISH_UPLOADS_DIR=%D/uploads
Environment=SILVERFISH_CONFIG_DIR=%D/config
WorkingDirectory=/usr/local
RootDirectory=/usr
Author
Member
Copy link

This was something systemctl security-analyze complained about, but I wasn't sure what an appropriate root would be in combination with DynamicUser so I doubt this was the best choice.

This was something `systemctl security-analyze` complained about, but I wasn't sure what an appropriate root would be in combination with `DynamicUser` so I doubt this was the best choice.
Contributor
Copy link

RootDirectory chroots inyo that directory, so it should probanly be /.

WorkingDirectory=~ sets it to the DynamicUser's home (/var/lib/silverfish I believe).

That's what I'd set it to

`RootDirectory` chroots inyo that directory, so it should probanly be `/`. `WorkingDirectory=~` sets it to the DynamicUser's home (`/var/lib/silverfish` I believe). That's what I'd set it to
Owner
Copy link

i agree with @jalil that RootDirectory should probably be /, i ran into some issues trying to run this as written

i agree with @jalil that `RootDirectory` should probably be `/`, i ran into some issues trying to run this as written
Author
Member
Copy link

@jalil, I'm unable to set WorkingDirectory=~ due to dynamic user; this is what gets logged:

silverfish.service: WorkingDirectory=~ is not allowed under DynamicUser=yes. Refusing.

@jalil, I'm unable to set `WorkingDirectory=~` due to dynamic user; this is what gets logged: `silverfish.service: WorkingDirectory=~ is not allowed under DynamicUser=yes. Refusing.`
@ -0,0 +19,4 @@
DynamicUser=yes
ProtectHome=yes
NoNewPrivileges=true
ExecStart=/usr/local/bin/silverfish serve --config-dir $SILVERFISH_CONFIG --tmp-path SILVERFISH_TMP_DIR --uploads-path SILVERFISH_UPLOADS_DIR --themes-path SILVERFISH_THEMES_DIR
Author
Member
Copy link

Note that the service doesn't actually run right now; it attempts to start then complains about the keygen step.

Note that the service doesn't actually run right now; it attempts to start then complains about the keygen step.
Owner
Copy link

I kinda wonder how we should handle this because those keys are sensitive and I don’t know how regular sensitive things are set these days outside of virtual hosts with a Secrets feature that sets env vars at runtime. Does systemd have anything for this?

I kinda wonder how we should handle this because those keys are sensitive and I don’t know how regular sensitive things are set these days outside of virtual hosts with a Secrets feature that sets env vars at runtime. Does systemd have anything for this?
Author
Member
Copy link

System credentials look like they would be a good fit here.

[System credentials](https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html) look like they would be a good fit here.
Contributor
Copy link

There are missing $ in those variables

There are missing `$` in those variables
Contributor
Copy link

And yes, systemd credentials are the perfect thing for this, you can decrypt a file and pass its value as an env var, or as a path to a decrypted temp file. You can also store the secret in plain text but make it only readable by root and systemd will make it available to the service anyways.

And yes, systemd credentials are the perfect thing for this, you can decrypt a file and pass its value as an env var, or as a path to a decrypted temp file. You can also store the secret in plain text but make it only readable by root and systemd will make it available to the service anyways.
Owner
Copy link

and as mentioned in my other comment, things that can be environment variables can just be set as environment variables and you don't need to pass them as CLI args.

and as mentioned in my other comment, things that can be environment variables can just be set as environment variables and you don't need to pass them as CLI args.
Owner
Copy link

@jalil you can do @include <some path> in the silverfish configs. Maybe we can pass --config <decrypted file> and that file can then @include "/etc/path/to/actual/config"?

@jalil you can do `@include <some path>` in the silverfish configs. Maybe we can pass `--config <decrypted file>` and that file can then `@include "/etc/path/to/actual/config"`?
Contributor
Copy link

Yup, that can be done

Yup, that can be done
@ -0,0 +22,4 @@
ExecStart=/usr/local/bin/silverfish serve --config-dir $SILVERFISH_CONFIG --tmp-path SILVERFISH_TMP_DIR --uploads-path SILVERFISH_UPLOADS_DIR --themes-path SILVERFISH_THEMES_DIR
Restart=on-failure
StartLimitInterval=120s
StartLimitBurst=3
Author
Member
Copy link

These settings will prevent the service from restarting more than 3 times in 120 seconds; I chose these numbers arbitrarily and am open to suggestions on better ones.

I could not find a way to recover from a rate limited restart within systemd, my understanding is this might need to be done manually but I am new to this depth of systemd stuff.

These settings will prevent the service from restarting more than 3 times in 120 seconds; I chose these numbers arbitrarily and am open to suggestions on better ones. I could not find a way to recover from a rate limited restart within systemd, [my understanding is this might need to be done manually](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#StartLimitIntervalSec=interval) but I am new to this depth of systemd stuff.
Owner
Copy link

Looks fine to me then

Looks fine to me then
Owner
Copy link

looks good to me, behaved as expected when i tested it.

looks good to me, behaved as expected when i tested it.
zkat marked this conversation as resolved
Author
Member
Copy link

You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory).

@jalil I didn't set these because they're not currently in use by silverfish, would they need to be set for any other reason?

> You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory). @jalil I didn't set these because they're not currently in use by silverfish, would they need to be set for any other reason?
@ -0,0 +11,4 @@
Type=exec
Environment=SILVERFISH_THEMES_DIR=%S/themes
Environment=SILVERFISH_TMP_DIR=%T
Environment=SILVERFISH_DB_DIR=%D/db
Author
Member
Copy link

Note this isn't used or passed in yet.

Note this isn't used or passed in yet.
Owner
Copy link

silverfish does a thing where environment variables can be passed in instead of command line arguments. The conversion is automatic so to pass in —foo-bar you would set SILVERFISH_FOO_BAR instead. They would get processed the same.

silverfish does a thing where environment variables can be passed in instead of command line arguments. The conversion is automatic so to pass in `—foo-bar` you would set `SILVERFISH_FOO_BAR` instead. They would get processed the same.
Owner
Copy link

the %D specifier is new enough (introduced in systemd v256, released may 2024) that my debian bookworm machine (still in full support til mid-2026, and LTS into 2028) can't parse it. could you please remove %D from these to improve portability?

the other specifiers seem to parse ok on that machine, which is running systemd 252.

the `%D` specifier is new enough (introduced in systemd v256, released may 2024) that my debian bookworm machine (still in full support til mid-2026, and LTS into 2028) can't parse it. could you please remove `%D` from these to improve portability? the other specifiers seem to parse ok on that machine, which is running systemd 252.
Contributor
Copy link

@sabrinagannon wrote in #166 (comment):

You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory).

@jalil I didn't set these because they're not currently in use by silverfish, would they need to be set for any other reason?

Not until they are in use

@sabrinagannon wrote in https://codeberg.org/conjured/silverfish/pulls/166#issuecomment-8612979: > > You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory). > > @jalil I didn't set these because they're not currently in use by silverfish, would they need to be set for any other reason? Not until they are in use
Owner
Copy link

@jalil wrote in #166 (comment):

@sabrinagannon wrote in #166 (comment):

You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory).

@jalil I didn't set these because they're not currently in use by silverfish, would they need to be set for any other reason?

Not until they are in use

We’re also having a conversation about where to put logs but you don’t have to worry about it for this PR

@jalil wrote in https://codeberg.org/conjured/silverfish/pulls/166#issuecomment-8613174: > @sabrinagannon wrote in #166 (comment): > > > > You should set the RuntimeDirectory, CacheDirectory, StateDirectory and LogsDirectory to silverfish, so that systemd creates these directories for you in the allropriate place (e.g. /var/lib/silverfish for the state directory). > > > > > > @jalil I didn't set these because they're not currently in use by silverfish, would they need to be set for any other reason? > > Not until they are in use We’re also having a conversation about where to put logs but you don’t have to worry about it for this PR
@ -0,0 +9,4 @@
[Service]
Type=exec
Environment=SILVERFISH_THEMES_DIR=%S/themes
Owner
Copy link

this expands to /var/lib/themes, could we change it to %S/silverfish/themes?

this expands to `/var/lib/themes`, could we change it to `%S/silverfish/themes`?
Contributor
Copy link

This is probably because StateDirectory=silverfish isn't set

This is probably because `StateDirectory=silverfish` isn't set
Author
Member
Copy link

When I try to add StateDirectory=silverfish, I get the following namespace related failures:

silverfish.service: Failed to set up mount namespacing: /var/lib/private/silverfish: No such file or directory
silverfish.service: Failed at step NAMESPACE spawning /usr/local/bin/silverfish: No such file or directory

This is the only directory I've been setting up, I'm not sure if they depend on each other or if it's incompatible with another setting?

When I try to add `StateDirectory=silverfish`, I get the following namespace related failures: ``` silverfish.service: Failed to set up mount namespacing: /var/lib/private/silverfish: No such file or directory silverfish.service: Failed at step NAMESPACE spawning /usr/local/bin/silverfish: No such file or directory ``` This is the only directory I've been setting up, I'm not sure if they depend on each other or if it's incompatible with another setting?
Contributor
Copy link

This is my forgejo runner's service:

[Unit]
After=network-online.target
Description=Gitea Actions Runner
Wants=network-online.target
[Service]
Environment="HOME=/var/lib/gitea-runner/native"
Environment="LOCALE_ARCHIVE=/nix/store/9vmxdn26pggj3glazmb68vhcf4smflvz-glibc-locales-2.40-66/lib/locale/locale-archive"
Environment="PATH=[REDACTED (too long)]"
Environment="TZDIR=/nix/store/xaa75rd44q62nc9mrbvym9d1m6gy0fj8-tzdata-2025b/share/zoneinfo"
DynamicUser=true
EnvironmentFile=/run/secrets/services/forgejo-runner/token
ExecStart=/nix/store/3dsj66ykgdx8m9hrp44wy2zdn6shfi3p-forgejo-runner-11.3.1/bin/act_runner daemon --config /nix/store/2bd7b0gqaka25j5f839gpcfl06bh75na-config.yaml
ExecStartPre=/nix/store/fvz2kxp6difjx3yrbjc648hqhhrvsq9h-gitea-register-runner-native
Restart=on-failure
RestartSec=2
StateDirectory=gitea-runner
User=gitea-runner
WorkingDirectory=-/var/lib/gitea-runner/native
[Install]
WantedBy=multi-user.target
This is my forgejo runner's service: ```service [Unit] After=network-online.target Description=Gitea Actions Runner Wants=network-online.target [Service] Environment="HOME=/var/lib/gitea-runner/native" Environment="LOCALE_ARCHIVE=/nix/store/9vmxdn26pggj3glazmb68vhcf4smflvz-glibc-locales-2.40-66/lib/locale/locale-archive" Environment="PATH=[REDACTED (too long)]" Environment="TZDIR=/nix/store/xaa75rd44q62nc9mrbvym9d1m6gy0fj8-tzdata-2025b/share/zoneinfo" DynamicUser=true EnvironmentFile=/run/secrets/services/forgejo-runner/token ExecStart=/nix/store/3dsj66ykgdx8m9hrp44wy2zdn6shfi3p-forgejo-runner-11.3.1/bin/act_runner daemon --config /nix/store/2bd7b0gqaka25j5f839gpcfl06bh75na-config.yaml ExecStartPre=/nix/store/fvz2kxp6difjx3yrbjc648hqhhrvsq9h-gitea-register-runner-native Restart=on-failure RestartSec=2 StateDirectory=gitea-runner User=gitea-runner WorkingDirectory=-/var/lib/gitea-runner/native [Install] WantedBy=multi-user.target ```
Owner
Copy link

oh yeah should probably want network-online.target yeah?

oh yeah should probably want `network-online.target` yeah?
sabrinagannon changed title from (削除) Add template silverfish.service as a user service (削除ここまで) to WIP: Add template silverfish.service as a user service 2025年12月01日 21:52:36 +01:00
Set environment in one line, pass to script, / is root directory
All checks were successful
CI Silverfish Stall / silverfish-stall-amd64 (pull_request) Successful in 3m44s
5ad4e52656
@ -0,0 +15,4 @@
DynamicUser=yes
ProtectHome=yes
NoNewPrivileges=true
ExecStart=/usr/local/bin/silverfish serve --config-dir $SILVERFISH_CONFIG_DIR --tmp-path $SILVERFISH_TMP_PATH --uploads-path $SILVERFISH_UPLOADS_PATH --themes-path $SILVERFISH_THEMES_PATH --database-path $SILVERFISH_DATABASE_PATH
Author
Member
Copy link

@zkat maybe I misunderstood your previous comments, but this was the only way I could pass the environment variables to silverfish successfully.

Other things I tried:

  1. Passing only the env vars:
ExecStart=/usr/local/bin/silverfish serve $SILVERFISH_CONFIG_DIR $SILVERFISH_TMP_PATH $SILVERFISH_UPLOADS_PATH $SILVERFISH_THEMES_PATH $SILVERFISH_DATABASE_PATH

Resulted in error: unexpected argument '/config' found; they were not recognized as the flag args.
2. Adjusting the env vars to better match the flag values, eg SILVERFISH_UPLOADS_PATH becomes SILVERFISH_UPLOADS-PATH: resulted in
Invalid environment assignment, ignoring: SILVERFISH_UPLOADS-PATH=/uploads

@zkat maybe I misunderstood your previous comments, but this was the only way I could pass the environment variables to silverfish successfully. Other things I tried: 1. Passing only the env vars: ``` ExecStart=/usr/local/bin/silverfish serve $SILVERFISH_CONFIG_DIR $SILVERFISH_TMP_PATH $SILVERFISH_UPLOADS_PATH $SILVERFISH_THEMES_PATH $SILVERFISH_DATABASE_PATH ``` Resulted in `error: unexpected argument '/config' found`; they were not recognized as the flag args. 2. Adjusting the env vars to better match the flag values, eg `SILVERFISH_UPLOADS_PATH` becomes `SILVERFISH_UPLOADS-PATH`: resulted in `Invalid environment assignment, ignoring: SILVERFISH_UPLOADS-PATH=/uploads`
Contributor
Copy link

You don't need to pass them to the CLI, it picks them up from the Environment

You don't need to pass them to the CLI, it picks them up from the Environment
Owner
Copy link

Yeah just don’t pass in extra arguments at all. As long as they’re set in the env you’re good

Yeah just don’t pass in extra arguments at all. As long as they’re set in the env you’re good
Author
Member
Copy link

My misunderstanding, thank you!

My misunderstanding, thank you!
@ -0,0 +10,4 @@
[Service]
Type=exec
Environment="SILVERFISH_CONFIG_DIR=/config" "SILVERFISH_UPLOADS_PATH=/uploads" "SILVERFISH_DATABASE_PATH=/db" "SILVERFISH_TMP_PATH=%T" "SILVERFISH_THEMES_PATH=%S/themes"
WorkingDirectory=/usr/local
Author
Member
Copy link

Maybe this is a silly question, but for working with the config file and credentials, where do I put the encrypted configuration file so that exists ahead of time for the service?

I would have expected to be able to put a config directory in /usr/local based on what I have here, but that does not work.

Maybe this is a silly question, but for working with the config file and credentials, where do I put the encrypted configuration file so that exists ahead of time for the service? I would have expected to be able to put a config directory in `/usr/local` based on what I have here, but that does not work.
Owner
Copy link

This I have no idea about. I didn’t even know until this PR that systemd supported this kind of thing!!

This I have no idea about. I didn’t even know until this PR that systemd supported this kind of thing!!
Contributor
Copy link

I use sops-nix which decrypts secrets to /run/secrets/ (which is a symlink to /run/secrets.d/$GENERATION so you can update the secrets without overwriting the files).

This is used for example:

  • Configuring a forgejo runner: EnvironmentFile=/run/secrets/services/forgejo-runner/token
  • Configuring harmonia (a nix cache): LoadCredential=sign-key-0:/run/secrets/services/harmonia/key

I don't know how you'd do this in general, but you could nudge people create a /secrets folder (chmod 700 /secrets) and load the encrypted config from there.

I use `sops-nix` which decrypts secrets to `/run/secrets/` (which is a symlink to `/run/secrets.d/$GENERATION` so you can update the secrets without overwriting the files). This is used for example: - Configuring a forgejo runner: `EnvironmentFile=/run/secrets/services/forgejo-runner/token` - Configuring `harmonia` (a nix cache): `LoadCredential=sign-key-0:/run/secrets/services/harmonia/key` I don't know how you'd do this in general, but you could nudge people create a `/secrets` folder (`chmod 700 /secrets`) and load the encrypted config from there.
sabrinagannon left a comment
Copy link

Okay, I think this is in a place where it's good to go, pending further feedback or asks.

What sets it apart now is that it runs!

Okay, I think this is in a place where it's good to go, pending further feedback or asks. What sets it apart now is that it runs!
@ -0,0 +8,4 @@
# 1. generate session key and csrf-salt: /usr/local/bin/silverfish keygen
# 2. store the output from 1 into /etc/silverfish/prod.kdl
# 3. encrypt the keys: systemd-creds encrypt /etc/silverfish/prod.kdl /etc/silverfish/prod-encrypted.kdl
# 4. safely destroy the unencrypted key file: shred -u /etc/silverfish/prod.kdl
Author
Member
Copy link

I didn't include the systemctl enable silverfish.service and systemctl start silverfish.service steps here, let me know if I should to be completely exhaustive!

I didn't include the `systemctl enable silverfish.service` and `systemctl start silverfish.service` steps here, let me know if I should to be completely exhaustive!
@ -0,0 +16,4 @@
[Service]
Type=exec
StateDirectory=silverfish
Author
Member
Copy link

I had to drop RootDirectory as a setting to get the service running. Otherwise I'd get No Such File or Directory errors when trying to use StateDirectory properly but I'm not 100% on why that's the case.

I had to drop `RootDirectory` as a setting to get the service running. Otherwise I'd get `No Such File or Directory` errors when trying to use StateDirectory properly but I'm not 100% on why that's the case.
@ -0,0 +21,4 @@
ProtectHome=yes
NoNewPrivileges=true
Environment="SILVERFISH_UPLOADS_PATH=%S/silverfish/uploads" "SILVERFISH_DATABASE_PATH=%S/silverfish/db" "SILVERFISH_TMP_PATH=%T" "SILVERFISH_THEMES_PATH=%S/silverfish/themes"
LoadCredentialEncrypted=prod-encrypted.kdl:/etc/silverfish/prod-encrypted.kdl
Author
Member
Copy link

https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#LoadCredential=ID:PATH provides a good overview of this; I chose /etc/silverfish somewhat arbitrarily.

https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#LoadCredential=ID:PATH provides a good overview of this; I chose `/etc/silverfish` somewhat arbitrarily.
@ -0,0 +22,4 @@
NoNewPrivileges=true
Environment="SILVERFISH_UPLOADS_PATH=%S/silverfish/uploads" "SILVERFISH_DATABASE_PATH=%S/silverfish/db" "SILVERFISH_TMP_PATH=%T" "SILVERFISH_THEMES_PATH=%S/silverfish/themes"
LoadCredentialEncrypted=prod-encrypted.kdl:/etc/silverfish/prod-encrypted.kdl
ExecStart=/usr/local/bin/silverfish serve --config %d/prod-encrypted.kdl --database-path $SILVERFISH_DATABASE_PATH --uploads-path $SILVERFISH_UPLOADS_PATH --themes-path $SILVERFISH_THEMES_PATH --tmp-path $SILVERFISH_TMP_PATH
Author
Member
Copy link
  1. I'm still passing env vars here because I could not get the service working without passing them directly unfortunately 😕 I'm not sure why.
  2. I decided to encrypt the entire config and pass it in directly for this initial pass at a service file because it worked with my understanding of what LoadCredentialsEncrypted does. I like Kat's suggestion better but it would require knowing things about CREDENTIALS_DIRECTORY that seems to be managed by systemd at runtime.
1. I'm still passing env vars here because I could not get the service working without passing them directly unfortunately 😕 I'm not sure why. 2. I decided to encrypt the entire config and pass it in directly for this initial pass at a service file because it worked with my understanding of what `LoadCredentialsEncrypted` does. I like [Kat's suggestion better](https://codeberg.org/conjured/silverfish/pulls/166#issuecomment-8613828) but it would require knowing things about `CREDENTIALS_DIRECTORY` that seems to be managed by systemd at runtime.
- fix type of service to be "exec"
- correct paths for where to store executable and where to put service
 unit file
- Set environment variables for paths needed by silverfish, pass those
 into ExecStart
Security improvements:
- Set DynamicUSer, ProtectHome to 'yes'
- Set NoNewPrivileges to 'true'
- WorkingDirectory and RootDirectory are set.
Restart behaviour:
- Adds a start limit to no more than 3 restart attempts within 120s
- Note: does NOT have behaviour to recover from when start limits have
 been exceeded, will need to decide on how we want to handle that.
Merge branch '162-systemd-service' of ssh://codeberg.org/conjured/silverfish into 162-systemd-service
All checks were successful
CI Silverfish / silverfish-amd64 (pull_request) Successful in 3m10s
2956f03752
sabrinagannon changed title from (削除) WIP: Add template silverfish.service as a user service (削除ここまで) to Add template silverfish.service as a user service 2025年12月04日 21:24:25 +01:00
Contributor
Copy link

Small nit, it could be placed in a contrib/systemd dir instead (so other integrations, including the flake, could also go there)

Small nit, it could be placed in a `contrib/systemd` dir instead (so other integrations, including the flake, could also go there)

i'll find some time to review tomorrow

i'll find some time to review tomorrow
Move service to contrib/systemd
All checks were successful
CI Silverfish / silverfish-amd64 (pull_request) Successful in 3m15s
0eeac2a33f
cjdesno left a comment
Copy link

Looks pretty good! A few questions and suggested changes.

Looks pretty good! A few questions and suggested changes.
@ -0,0 +1,31 @@
# Service file template for silverfish.
# Setup:
Owner
Copy link

it looks like we also need to install a theme? unless i'm misunderstanding something about first-time bringup. (the service crashed due to no index.html, for me)

it looks like we also need to install a theme? unless i'm misunderstanding something about first-time bringup. (the service crashed due to no index.html, for me)
Contributor
Copy link

@cjdesno the default theme should be baked into the binary (via the DefaultTheme struct). It uses rust-embed to bake it in, which I know works differently between debug and release builds by default... maybe that's what could've caused the error you were seeing?

anyway, for this PR, I feel like the systemd service should assume that the Silverfish binary itself will provide and/or configure the default theme

@cjdesno the default theme _should_ be baked into the binary (via the [`DefaultTheme`](https://codeberg.org/conjured/silverfish/src/commit/f482d135dd656953d51b8ddbfa9dcaf2a57d1097/crates/silverfish-theme/src/lib.rs#L30) struct). It uses [`rust-embed`](https://crates.io/crates/rust-embed) to bake it in, which I know works differently between debug and release builds by default... maybe that's what could've caused the error you were seeing? anyway, for this PR, I feel like the systemd service should assume that the Silverfish binary itself will provide and/or configure the default theme
Author
Member
Copy link

I agree with Kyle.
Ideally these steps will be short lived and removed once there's a complete pipeline for release/installation, since they're pretty technical as it is. I don't want to get more in the weeds or prescriptive than I have to with them.

I agree with Kyle. Ideally these steps will be short lived and removed once there's a complete pipeline for release/installation, since they're pretty technical as it is. I don't want to get more in the weeds or prescriptive than I have to with them.
cjdesno marked this conversation as resolved
@ -0,0 +2,4 @@
# Setup:
# 1. copy the silverfish binary to /usr/local/bin
# 2. copy this file to /etc/systemd/system and update the configuration to your preferences
# 3. create database: /usr/local/bin/silverfish db create --db-path SILVERFISH_DATABASE_PATH
Owner
Copy link

--db-path should be --database-path

Also the database path is defined later in the file only as a template path, so it's challenging to get this step done. i had to know that %S expands to /var/lib, and then run the service and let it fail to create the dir with correct permissions, and then i was able to run this step (but again by already knowing that %S means /var/lib on my machine). Maybe we can add another note here to help with that, or something?

`--db-path` should be `--database-path` Also the database path is defined later in the file only as a template path, so it's challenging to get this step done. i had to know that %S expands to /var/lib, and then run the service and let it fail to create the dir with correct permissions, and then i was able to run this step (but again by already knowing that %S means /var/lib on my machine). Maybe we can add another note here to help with that, or something?
Author
Member
Copy link

For sure, I'll just hardcode it for now. %S could mean something different for user managed services but since this is going under system, I think we're safe to keep it simple.

For sure, I'll just hardcode it for now. `%S` could mean something different for user managed services but since this is going under system, I think we're safe to keep it simple.
@ -0,0 +20,4 @@
DynamicUser=yes
ProtectHome=yes
NoNewPrivileges=true
Environment="SILVERFISH_UPLOADS_PATH=%S/silverfish/uploads" "SILVERFISH_DATABASE_PATH=%S/silverfish/db" "SILVERFISH_TMP_PATH=%T" "SILVERFISH_THEMES_PATH=%S/silverfish/themes"
Owner
Copy link

if instead of SILVERFISH_UPLOADS_PATH you set SF_CONFIG_UPLOADS_PATH, and SF_CONFIG_DATABASE_PATH, etc, then you don't need to pass the command-line args in the exec line because silverfish will detect the envs automatically.

if instead of `SILVERFISH_UPLOADS_PATH` you set `SF_CONFIG_UPLOADS_PATH`, and `SF_CONFIG_DATABASE_PATH`, etc, then you don't need to pass the command-line args in the exec line because silverfish will detect the envs automatically.
Author
Member
Copy link

Thanks! I was trying SILVERFISH_... before; this explains why it wasn't working 😅

Thanks! I was trying `SILVERFISH_...` before; this explains why it wasn't working 😅
Address @cjdesno 's review comments
All checks were successful
CI Silverfish / silverfish-amd64 (pull_request) Successful in 3m17s
58b8d14949
- Clearer setup steps with correct flag.
- Use `SF` prefixed environment variables to automatically pass in.
cjdesno left a comment
Copy link

Needs one small fix for the envs, otherwise ready to go!

Needs one small fix for the envs, otherwise ready to go!
@ -0,0 +20,4 @@
DynamicUser=yes
ProtectHome=yes
NoNewPrivileges=true
Environment="SF_UPLOADS_PATH=%S/silverfish/uploads" "SF_DATABASE_PATH=%S/silverfish/db" "SF_TMP_PATH=%T" "SF_THEMES_PATH=%S/silverfish/themes"
Owner
Copy link

These need to be SF_CONFIG_UPLOADS_PATH, SF_CONFIG_DATABASE_PATH, etc (you need to add CONFIG after SF in all of them)

These need to be `SF_CONFIG_UPLOADS_PATH`, `SF_CONFIG_DATABASE_PATH`, etc (you need to add `CONFIG` after `SF` in all of them)
Author
Member
Copy link

What I get for not double checking!
Thanks!

What I get for not double checking! Thanks!
sabrinagannon marked this conversation as resolved
Fixup env var names - needs to be SF_CONFIG
All checks were successful
CI Silverfish / silverfish-amd64 (pull_request) Successful in 3m24s
848e11ae90
@ -0,0 +5,4 @@
# 3. create database: /usr/local/bin/silverfish db create --database-path var/lib/SILVERFISH_DATABASE_PATH
# 4. migrate database: /usr/local/bin/silverfish db migrate --database-path var/lib/SILVERFISH_DATABASE_PATH
# 5. encrypt secrets into a prod-encrypted.kdl file at /etc/silverfish:
# 1. generate session key and csrf-salt: /usr/local/bin/silverfish keygen
Owner
Copy link

there's actually a --save flag for keygen that will let you combine steps 1 and 2 here.

there's actually a `--save` flag for `keygen` that will let you combine steps 1 and 2 here.
@ -0,0 +12,4 @@
[Unit]
Description=Runs silverfish ecommerce software
Documentation=https://codeberg.org/conjured/silverfish
Owner
Copy link

Do we want

After=network-online.target
Wants=network-online.target

here too?

Do we want ```systemd After=network-online.target Wants=network-online.target ``` here too?
Contributor
Copy link

(削除) A bit of a technicallity, but we may not want network-online.target since we don't need to be online for silverfish to run, we can still accept connections from the LAN (and NetworkManager has known issues that are resolved by not checking that it is online when activating network-online.target https://wiki.archlinux.org/title/NetworkManager#NetworkManager-wait-online). (削除ここまで)

(削除) I think the correct target is network.target, since we need to be able to access the network, but not necessarily be online. (削除ここまで)

~~A bit of a technicallity, but we may not want `network-online.target` since we don't _need_ to be online for `silverfish` to run, we can still accept connections from the LAN (and NetworkManager has known issues that are resolved by not checking that it is online when activating `network-online.target` https://wiki.archlinux.org/title/NetworkManager#NetworkManager-wait-online).~~ ~~I think the correct target is `network.target`, since we need to be able to access the network, but not necessarily be online.~~
Contributor
Copy link

network-online.target seems to be correct, I just have bad personal experiences with it (as a user of a linux PC, not as a server admin)

`network-online.target` seems to be correct, I just have bad personal experiences with it (as a user of a linux PC, not as a server admin)
Owner
Copy link

sounds good, then

sounds good, then
zkat marked this conversation as resolved
zkat left a comment
Copy link

Couple of small comments but this looks really great.

Couple of small comments but this looks really great.
pass the --save option
All checks were successful
CI Silverfish / silverfish-amd64 (pull_request) Successful in 3m13s
ca3f68d333
sabrinagannon deleted branch 162-systemd-service 2025年12月11日 01:57:19 +01:00
Sign in to join this conversation.
No reviewers
Labels
Clear labels
Compat
Breaking
Breaking change that won't be backward compatible
Flag/Good First Issue
Good issue for first-time contributors
Kind/Accessibility
Accessibility issue, bug or otherwise
Kind/Appearance
Design, styling, and other aesthetic and visual items
Kind/Bug
Something is not working
Kind/Compliance
Legal, policy, or some other kind of compliance
Kind/DevOps
CI/CD, releases, etc
Kind/Documentation
Documentation changes
Kind/Enhancement
Improve existing functionality
Kind/Feature
New functionality
Kind/Performance
Gotta go fast
Kind/Security
This is security issue
Kind/Technical Improvement
Underlying technical improvement that is not necessarily user-impacting or visible.
Kind/Testing
Issue or pull request related to testing
Kind/UX
Related to user experience/product
Priority
Critical
The priority is critical
Priority
High
The priority is high
Priority
Low
The priority is low
Priority
Medium
The priority is medium
Reviewed
Confirmed
Issue has been confirmed
Reviewed
Duplicate
This issue or pull request already exists
Reviewed
Invalid
Invalid issue
Reviewed
Won't Fix
This issue won't be fixed
Size
L
Significant change
Size
M
Medium-size change
Size
S
Small change
Size
XL
Very large change that might take months to complete and impact many components
Size
XS
Trivially small change
Status
Abandoned
Somebody has started to work on this but abandoned work
Status
Blocked
Something is blocking this issue or pull request
Status
Need More Info
Feedback is required to reproduce issue or to continue work
Status
Needs Design
Requires design/review from Alchemists (product/UX)
Status
Needs Discussion
A discussion needs to happen before implementation
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
7 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
conjured/silverfish!166
Reference in a new issue
conjured/silverfish
No description provided.
Delete branch "162-systemd-service"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?