Skip to content

Deployment

This page talks a bit about deploying bovine. For this, we will use the simplest bovine_herd application possible given by

from quart import Quart

from bovine_herd import BovineHerd
from bovine_pubsub import BovinePubSub

app = Quart(__name__)
BovinePubSub(app)
BovineHerd(app)

We will assume that it is saved in a file app.py and one has a python environment, where both bovine_herd and bovine_pubsub are installed. If this is the case, you should be able to run

hypercorn app:app

and open the bovine application actor at http://localhost:8000/activitypub/bovine.

To deploy this in a production environment, you will want to make some changes. For example add a landing page via

@app.get('/')
async def index():
    return "Welcome to my bovine server"

or configure the database beyond being an sqlite file. I currently use postgres.

Systemd unit

The following systemd unit file can be used to run the above app with systemd.

[Unit]
Description=Bovine
After=network.target

[Service]
User=bovine
Group=bovine
Restart=always
Type=simple
WorkingDirectory=/opt/bovine
LimitAS=infinity
LimitRSS=infinity
LimitCORE=infinity
LimitNOFILE=65536
ExecStart=/usr/local/bin/poetry run hypercorn app:app --bind unix:/run/bovine.sock -m 777

[Install]
WantedBy=multi-user.target

Under ubuntu place this file in /etc/systemd/system/ and then reload systemd via systemctl daemon-reload.

The settings starting with Limit are not fine tuned. In particular, the number of allowed file connections is needed in order to handle the many GET requests from fellow Fediverse servers, when somebody announces your content.

The default value of the number of allowed open files can be viewed on your system with ulimit -n. Having too low number of open files leads to errors such as

 [2023-02-07 19:16:10,518] ERROR    asyncio      socket.accept() out of system resource
 socket: <asyncio.TransportSocket fd=3, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0, laddr=/tmp/bovine.sock>
 Traceback (most recent call last):
 File "/usr/lib/python3.10/asyncio/selector_events.py", line 159, in_accept_connection
  conn, addr = sock.accept()
 File "/usr/lib/python3.10/socket.py", line 293, in accept
 OSError: [Errno 24] Too many open files

Nginx

Nginx can then be configured via in sites-available

 location / {
  proxy_set_header Host $http_host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header Upgrade $http_upgrade;
  proxy_redirect off;
  proxy_buffering off;
  proxy_pass <http://unix:/run/bovine.sock>;
 }

Furthermore, one needs to do the usual gymnastics to get SSL working.

Finally, one needs to edit the nginx config, i.e. /etc/nginx/nginx.conf and increase the number of worker connections, e.g.

 events {
        worker_connections 4096;
 }

This is again necessary to handle the many get requests that occur if somebody announces your content. The corresponding error message is

2023/02/11 13:21:46 [alert] 650#650: 768 worker_connections are not enough

Furhermore, the error message

 2023/02/20 11:58:43 [alert] 54804#54804: *7206  socket() failed (24: Too many open files) while connecting to upstream,

can be hopefully be fixed by adding

worker_rlimit_nofile 8192;

to nginx.conf (this one belongs outside the event block).