Developing a blazing fast website in Python using Falcon and Bjoern

Khalid AlnajjarWeb Development Leave a Comment

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