Few days back, I wanted to develop a web service in Python. I wanted to run the service on my VPS with as minimal resources as possible while providing a fast service. I started looking for benchmarks online of different Python web frameworks and WSGI servers, and found out about two awesome libraries, falcon and bjoern.
Falcon is a micro-framework that is designed for building very fast micro-services. It is very flexible as it permits you to install add-ons and other libraries (e.g. Jinja2) easily. Just what I was looking for. On the other hand, Bjoern is a “A screamingly fast, ultra-lightweight WSGI server”, as their Github page says. It uses around 600KB of memory. 600KB, imagine how light it is!
In this post, I will explain how to setup and use Falcon with Bjoern for serving efficient websites 🙂
Installation
I will assume that you have Python, either 2.7 or 3, installed. If you don’t, install it before proceeding with the tutorial. Let the fun begin!
Installing Falcon and developing your service
The first thing to do is to install Falcon, follow the installation steps from falcon’s website. Don’t proceed with installing any WSGI servers as we will use bjoern. Once you have installed falcon, implement your falcon service by creating Resources and link them to your Falcon app. For more details, follow the tutorial provided by falcon.
Hosting your app with Bjoern
To host your website with Bjoern, you need to install “libev-dev” as it depends on it. On Ubuntu and Debian, run the below command to install the library.
sudo apt-get -y install libev-dev
Now, you have the system requirements setup. What we will do next is create a file for serving the service where we attach the service app (Falcon’s API) to Bjoern. Name the file something like “app.py” and copy-paste the below code to the file while changing Falcon’s resources to yours.
import falcon import bjoern from pages import IndexResource from ipaddress import ip_address wsgi_app = api = application = falcon.API() # -- Edit Here -- api.req_options.auto_parse_form_urlencoded = True api.add_route('/', IndexResource()) # attach resources to API # -- End of Edit -- if __name__ == '__main__': import argparse # for parsing passed parameters through terminal parser = argparse.ArgumentParser() parser.add_argument("-ip", help="Hostname", default='0.0.0.0:8000', nargs='?') # either define an IP parser.add_argument("-socket", help="Linux Socket Name", default=None, nargs='?') # or pass path of Linux's socket args = parser.parse_args() if args.socket: # a socket is passed bjoern.run(wsgi_app, 'unix:' + args.socket) else: if ':' in args.ip: ip, separator, port = args.ip.rpartition(':') ip = ip_address(ip.strip("[]")) port = int(port) else: ip = ip_address(args.ip.strip("[]")) port = 8000 ip = str(ip) bjoern.run(wsgi_app, ip, port)
When the code above is executed, it will attach your falcon’s app to bjoern server by binding it to either a TCP IP and port or to a Linux socket. You can select the type of binding by using the parameters -ip and -socket. By default, this script will bind the app to all connections from the port 8000.
Before proceeding to mapping a domain to our bjoern server, let’s try that the service works locally by executing the below command and visiting http://127.0.0.1:8000.
python app.py -ip 127.0.0.1:8000
Pointing a domain name to Bjoren server
You have reached to this point, great! You are almost done configuring your robust web service. In this post, I will use Apache and define a proxy pass to the service from requests coming to a given domain. Alternatively, you can achieve the same with Nginx.
To install apache2, follow this tutorial. Then, fire up the terminal and run the below commands to install and activate Apache’s proxy mod.
sudo apt-get install libapache2-mod-proxy-html sudo a2enmod proxy sudo a2enmod proxy_http
To create a virtual host and point a domain to it, create a file in “/etc/apache2/sites-available/” and name it to your desired domain name with .conf as extension. Next, write the configuration below to it with configuring the ServerName, IP:Port, and Log paths.
<VirtualHost *:80> ServerName service.khalidalnajjar.com <Location /> ProxyPass http://127.0.0.1:8000/ ProxyPassReverse http://127.0.0.1:8000/ </Location> <Proxy *> allow from all </Proxy> ErrorLog /var/log/bjoren-falcon-service-error.log CustomLog /var/log/bjoren-falcon-service-access.log combined </VirtualHost>
After you have done that, execute sudo a2ensite conf-file.conf in the terminal followed by sudo service apache2 restart . Hopefully nothing went wrong and everything ran smoothly.
Now, we need to create an auto-start service so that our web service is always alive. To do so, create a file named something like “service-name.service” under “/lib/systemd/system/” and give it 644 permission.
touch /lib/systemd/system/service-name.service chmod 644 /lib/systemd/system/service-name.service
Thereafter, let’s define the service we want to run by the system by declaring the below settings in “service-name.service” file. Change the settings to match your setup.
[Unit] Description=Service name [Service] User=www-data Group=www-data ExecStart=/var/www/python/bjoren-service/venv/bin/python /var/www/python/bjoren-service/service/app.py -ip 127.0.0.1:8000 StandardOutput=syslog StandardError=syslog SyslogIdentifier=bjoren-service Restart=always [Install] WantedBy=multi-user.target
Below are some useful systemctl commands to assist you in setting up and running the service.
systemctl daemon-reload # reloading settings systemctl --state=failed # checking which services failed systemctl enable service-name.service # enabling a service systemctl start service-name.service # starting a service systemctl restart service-name.service # restarting a service systemctl status service-name.service # get status regarding a service
Conclusion
In conclusion, we have seen how to write, configure and run an insanely fast web service using Falcon and Bjoern. Using Apache and proxy passing the requests through it might slow down the requests a bit. However, I haven’t experimented with other alternatives.
Happy coding and serving efficient web sites. 🙂
* (This post contains affiliate links. Please read my disclosures for more details).
Share this Post