Package: autocert
autocertAutomatic TLS cert issuance and renewal for Python web appsOverviewAutocert is a package for automatically obtaining and renewing TLS certificates fromLet's Encryptusing theACMEprotocol.
It is based on the API and design of theGopackage with the same name:autocert.
To work its magic, autocert only requires a single TCP socket listening on your desired HTTPS port (usually 443).
This can come directly from an application or from a management system such assystemd.MotivationI often find myself with the need to host simple Python web apps as demos for friends / clients.
In these situations, I want the demo to be properly secured viaHTTPSbut I don't want to worry about the extra infrastructure that comes with setting up a reverse proxy (NGINX,Caddy, etc).
This library allows you to add an auto-renewing TLS certificate fromLet's Encryptto your website with a single line of code.There is quite a bit of dogma surrounding the hosting of Python-based web applications.
Most folks believe that utilizing areverse proxyis a hard requirement for achieving a secure, fast, and reliable deployment.
However, I really like the simplicity of hosting aFlaskorDjangoapp by combining a pure-PythonWSGI server(such asWaitress) with this project.
It might not be the best deployment option for a high-traffic, business-critical applications but it can easily support a few hundred requests per second on a smallDigital Oceandroplet.InstallIf you are unfamiliar withvirtual environments, I suggest taking a brief moment to learn about them and set one up.
The Python docs provide a greattutorialfor getting started with virtual environments and packages.Autocert can be installed via pip:pip install autocertExamplesThese examples utilize theWaitressWSGI server but you can follow your own preference.
However, whichever server you choose must be able to accept pre-listening sockets (you'll see what I mean).
More examples can be found in theexamples directory.Waitress can be installed via pip:pip install waitressbasicHere is a basic example of autocert usage (requires root):fromautocertimportautocert,wsgiimportsocketimportwaitress# open a socket on port 443s443=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s443.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)s443.bind(('0.0.0.0',443))s443.listen()# setup automatic cert issuance and renewals443_tls=autocert.manage(s443,'example.org','www.example.org',accept_tos=True)# serve your app with TLS!waitress.serve(wsgi.hello_world_app,sockets=[s443_tls],url_scheme='https')systemd w/ redirectHere is an example of using autocert with systemd sockets and an HTTP->HTTPS redirect:fromautocertimportautocert,wsgiimportosimportsocketimportthreadingimportwaitress# make sure systemd PID matchesifos.environ['LISTEN_PID']!=str(os.getpid()):raiseSystemExit('Mismatched LISTEN_PID')# expecting 2 ports here: 80, 443ifos.environ['LISTEN_FDS']!='2':raiseSystemExit('Expected 2 socket fds for ports 80 and 443')# create sockets from the fds opened by systemds80=socket.fromfd(3,socket.AF_INET,socket.SOCK_STREAM)s443=socket.fromfd(4,socket.AF_INET,socket.SOCK_STREAM)# start autocert's wsgi.redirect_app in a background threadt=threading.Thread(target=waitress.serve,args=(wsgi.redirect_app,),kwargs={'sockets':[s80]},daemon=True,)t.start()# setup automatic cert issuance and renewals443_tls=autocert.manage(s443,'example.org','www.example.org',accept_tos=True)# serve your app with TLS!waitress.serve(wsgi.hello_world_app,sockets=[s443_tls],url_scheme='https')TestingAutocert is tested usingpytest. Unit tests can be executed without anything special but the integration tests expect a locally-running ACME server. Runningpebblein a container is a great way to accomplish this!To run the tests, first install pytest:pip install pytestThen, unit tests can be ran via:pytest tests/unit/The integration tests need that local ACME server so let's start it up and set some necessary vars:docker run -p 14000:14000 --detach letsencrypt/pebbleNow the integration tests can be ran:pytest tests/integration/