Search code examples
linuxsystemdbottle

Why does my bottle server fail at startup?


I have written a little server using python and bottle and a systemd unit to install it as a service on xubuntu. The python script works as intended, and the service works fine if I start it from the command line (sudo systemctl advairMeter), but it fails at system startup.

Here is my .service file:

saul@linuxBox:~/Desktop$ cat /etc/systemd/system/advairMeter.service
[Unit]
Description=Advair meter
After=network.target

[Service]
ExecStart=/usr/bin/python3  server.py
Restart=always
WorkingDirectory=/home/saul/Projects/PythonProjects/medSched/

[Install]
WantedBy=multi-user.target

This is what happens at reboot:

Apr 09 08:43:49 linuxBox systemd[1]: Started Advair meter.
Apr 09 08:43:49 linuxBox python3[1176]: Bottle v0.12.19 server starting up (using WSGIRefServer())...
Apr 09 08:43:49 linuxBox python3[1176]: Listening on http://192.168.1.103:8080/
Apr 09 08:43:49 linuxBox python3[1176]: Hit Ctrl-C to quit.
Apr 09 08:43:50 linuxBox python3[1176]: Traceback (most recent call last):
Apr 09 08:43:50 linuxBox python3[1176]:   File "server.py", line 95, in <module>
Apr 09 08:43:50 linuxBox python3[1176]:     run(host='192.168.1.103', port=8080)
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/local/lib/python3.8/dist-packages/bottle.py", line 3137, in run
Apr 09 08:43:50 linuxBox python3[1176]:     server.run(app)
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/local/lib/python3.8/dist-packages/bottle.py", line 2789, in run
Apr 09 08:43:50 linuxBox python3[1176]:     srv = make_server(self.host, self.port, app, server_cls, handler_cls)
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/lib/python3.8/wsgiref/simple_server.py", line 154, in make_server
Apr 09 08:43:50 linuxBox python3[1176]:     server = server_class((host, port), handler_class)
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/lib/python3.8/socketserver.py", line 452, in __init__
Apr 09 08:43:50 linuxBox python3[1176]:     self.server_bind()
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/lib/python3.8/wsgiref/simple_server.py", line 50, in server_bind
Apr 09 08:43:50 linuxBox python3[1176]:     HTTPServer.server_bind(self)
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/lib/python3.8/http/server.py", line 138, in server_bind
Apr 09 08:43:50 linuxBox python3[1176]:     socketserver.TCPServer.server_bind(self)
Apr 09 08:43:50 linuxBox python3[1176]:   File "/usr/lib/python3.8/socketserver.py", line 466, in server_bind
Apr 09 08:43:50 linuxBox python3[1176]:     self.socket.bind(self.server_address)
Apr 09 08:43:50 linuxBox python3[1176]: OSError: [Errno 99] Cannot assign requested address
Apr 09 08:43:50 linuxBox systemd[1]: advairMeter.service: Main process exited, code=exited, status=1/FAILURE
Apr 09 08:43:50 linuxBox systemd[1]: advairMeter.service: Failed with result 'exit-code'.
Apr 09 08:43:50 linuxBox systemd[1]: advairMeter.service: Scheduled restart job, restart counter is at 4.
Apr 09 08:43:50 linuxBox systemd[1]: Stopped Advair meter.

Now the first part of the journalctl output above,

Bottle v0.12.19 server starting up (using WSGIRefServer())...
Listening on http://192.168.1.103:5678/
Hit Ctrl-C to quit.

is what I see if I just run the python script with python3 server.py, so it looks like the script actually executes, and then it makes sense that the address can't be assigned, since there's already a socket using it, but then why isn't there a process listening on that post once reboot is complete?

The python script itself is very simple,

<SNIP>
@route('/')
@auth_basic(is_authenticated_user)
def home():
   <SNIP>
run(host='192.168.1.103', port=8080)

I assume the mistake is in my .service file, but I haven't been able to find anything on the web that tells me how to fix it. This is my first experience with both bottle and systemd, so I'm likely making a very simple error.


Solution

  • There is a solid chance your service is running before your network has been set up during boot. That means that your OS doesn't have any network interfaces to listen on, and therefore your script would fail. To fix that, change your [Unit] section to this:

    [Unit]
    Description=Advair meter
    Wants=network-online.target
    After=network.target network-online.target
    

    You can check Cause a script to execute after networking has started? for more details.