svenstaro/miniserve

Miniserve keeps stopping; Unable to configure systemd using documentation guide

kohloth opened this issue · 5 comments

Really love this server and its simplicity and portability. However, I am having trouble with running it.

When I log onto my server with SSH, I want to start up miniserve, and then be able to exit out of SSH without killing miniserve too. I cannot see what the expected way of doing this is, and I cannot see an option (for example --background) for this, so I use miniserve & and then close the terminal.

The problem I am experiencing is that miniserve seems to run for several hours, and then spontaneously dies. So I am wondering if I am initating a background process in the wrong way - I believe the docs should describe this but do not?

In an attempt to fix this, I have tried using a monitored background process, as the docs do describe - systemd.

However, I cannot get this to work. When following the docs, and then attempting to start the process as per the docs (systemctl enable --now miniserve@-my-serve-path) I just see an error, which is Failed to start miniserve@.service: Unit name miniserve@.service is missing the instance name., which does not make any sense to me (I don't know what an instance name is), and searches for this error don't reveal anything about the nature of the problem. I am actually using this command systemctl enable --now /home/kohloth/test-site/server/miniserve@.service. When reading the docs, I could see they probably meant that -my-serve-path should be substituted for something else, but I wasn't sure exactly what.

I really like miniserve - thanks for this cool binary! But I feel like I am being forced to use something else. Do you know how I might fix this problem?

Hey, first of all great to hear you like miniserve. Thankfully, I think your issue can easily be fixed. First of all, if you want to background applications the dirty way (e.g. without systemd), you'd have to use some kind of process that keeps running in the user session. For instance, you could use tmux for that. Shell backgrounding (using &) only works so long as the shell is alive and the shell will be killed once you disconnect.

However, the recommended systemd way is definitely the way to go. You almost had it. If you want to serve /home/kohloth/test-site/server, you can use systemd-escape to figure out what the path must look like when given to systemd: systemd-escape /home/kohloth/test-site/server: -home-kohloth-test\x2dsite-server.

You can then use that funky looking escaped path and slap it into the enable line: systemctl enable --now miniserve@-home-kohloth-test\x2dsite-server. Hope that helps!

Thanks for your quick reply @svenstaro, I appreciate your help!

I understand the substitution pattern now. The example made it click. I sat down and tried to get this running again, but having followed these instructions closely, and having also made some further internet searches, I cannot get miniserve working with systemd. I am not sure if the problem is with miniserve, systemd, or some aspect of my server (its a simple Digital Ocean box, Ubuntu 20.04 (LTS) x64, no customisations).

I think the most likely thing is that I am doing something wrong, so I've attached the exact steps I have taken - please let me know if there is an error here. If not, could you attach a link to some docs that describe how to debug this here or in the readme?

Thank you!

Steps I've taken to configure miniserve with systemd on the Ubuntu box are:

1: Copied https://github.com/svenstaro/miniserve/blob/master/packaging/miniserve%40.service to /home/kohloth/test/server/miniserve@.service

  1. Edited /home/kohloth/test/server/miniserve@.service to adjust miniserve invocation. Only line changed is the one that begins with ExecStart=. Entire contents of the file is now:
[Unit]
Description=miniserve for %i
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]
ExecStart=/home/kohloth/test/server/miniserve --port=443 --spa --index=index.html --hidden --tls-cert=/home/kohloth/test/certs/test_com.crt --tls-key=/home/kohloth/test/certs/test_com.key /home/kohloth/test/public -- %I

IPAccounting=yes
IPAddressAllow=localhost
IPAddressDeny=any
DynamicUser=yes
PrivateTmp=yes
PrivateUsers=yes
PrivateDevices=yes
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_DAC_READ_SEARCH

[Install]
WantedBy=multi-user.target
  1. Ran systemd-escape /home/kohloth/test/server, which output -home-kohloth-test-server.

  2. Ran systemctl enable --now miniserve@-home-kohloth-test-server.
    Output was Created symlink /etc/systemd/system/multi-user.target.wants/miniserve@-home-kohloth-test-server.service → /home/kohloth/test/server/miniserve@.service and nothing else, so it seems to me like it worked perhaps.

Visited URL of site, no response to browser.

  1. Ran systemctl list-units --type=service as per internet search recommendation, to try verify that the process is running ok.
    However, output was ● miniserve@-home-kohloth-test-server.service loaded failed failed miniserve for -home-kohloth-test-server. So it seems that I can't see the site in the browser because systemd failed to start miniserve. But unsure why this is with the info that the output of this command provides.

  2. Ran systemctl status miniserve@-home-kohloth-test-server as per internet search to try and diagnose.
    Output was:

● miniserve@-home-kohloth-test-server.service - miniserve for -home-kohloth-test-server
     Loaded: loaded (/etc/systemd/system/miniserve@-home-kohloth-test-server.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Tue 2023-02-14 13:15:50 UTC; 1min 1s ago
    Process: 2559996 ExecStart=/home/kohloth/test/server/miniserve --port=443 --spa --index=index.html --hidden --tls-cert=/home/kohloth/test/certs/test_com.>
   Main PID: 2559996 (code=exited, status=203/EXEC)
         IP: 0B in, 0B out

But again, the output of this command has not shed much light on the problem.

Systemd documentation seems quite intense for a humble frontend dev like myself and with no obvious point of entry (except whole thing, beginning-to-end!), so I'm wondering again if it would be more practical to switch to a different server than to obtain a doctorate in systemd unix admin! But really don't want to, cos miniserve is awesome, and apart from this aspect of process management, really nice to use!

Hopefully I am just doing something small wrong!

What usually helps in your case is journalctl -r -u miniserve. It'll show you the last messages from top to bottom. However, in your case, I believe the mistake you made was while modifying the service file:
ExecStart=/home/kohloth/test/server/miniserve --port=443 --spa --index=index.html --hidden --tls-cert=/home/kohloth/test/certs/test_com.crt --tls-key=/home/kohloth/test/certs/test_com.key /home/kohloth/test/public -- %I
There's now two serving paths: The first is /home/kohloth/test/public and the second one is %I. Remove the first one and you should be good to go.

You should also be aware that this is a fairly restrictive unit file on purpose. If you then want to access miniserve from the outside directly, you might want to get rid of

IPAccounting=yes
IPAddressAllow=localhost
IPAddressDeny=any

@svenstaro Got it working now! Thanks for pointing me in the right direction. I encountered a few problems with diagnosing and fixing systemd config. For posterity, this is what has worked for me.

The commands journalctl -r -u miniserve and the basic journalctl both only ever returned "No entries" as their output, so I could not see any error messages to diagnose the problem with. I found that systemd logs were not enabled, and I enabled them by:

  1. Editing /etc/systemd/journald.conf with vim /etc/systemd/journald.conf, and then changing the line # Storage=auto to Storage=persistent
  2. Restarting the systemd journal process with sudo systemctl restart systemd-journald

When I tried to restart miniserve with systemd using systemctl enable --now miniserve@-home-kohloth-test\x2dsite-server, I could then see the error messages by using journalctl. (journalctl -r -u miniserve actually still said "No entries").

There were then a few permissions-related things that were problematic.

  1. It seems that the binary could not be executed while in the home directory (systemd config was the cause of course), so I copied it to /usr/local/bin/miniserve, and adjusted the server/miniserve@.service file to point to the new location.
  2. When being run by systemd, miniserve could not access the TLS cert files, so I changed the permissions of these files.
  3. Finally, systemd complained that it could not start the service on port 443 - permission denied again. As you say, the config provided at https://github.com/svenstaro/miniserve/blob/master/packaging/miniserve%40.service is quite locked down (which I appreciate the logic of). I used a more generic systemd config and it works fine now. (The [service] section now only contains this):
[Service]
Environment=SYSTEMD_LOG_LEVEL=debug 
Type=simple
Restart=always
RestartSec=5s
ExecStart=(Just as before - see previous post)

Thanks again for miniserve. Its about a million times better than carrying a ton of node_modules around or maintaining a LAMP stack! 👍

Glad to hear it now works. :)

I should have been more specific with journalctl: you need to run it on exactly the enabled unit and not just the template. That is, you have to feed journalctl the same name you also feed to systemctl enable.