Deploying ASGI sites on PythonAnywhere (beta)
Disclaimer¶
This help page explains how to set up an ASGI site on PythonAnywhere -- for example, one based on the FastHTML or FastAPI frameworks, or using the latest Django async features. We have a separate help page for Flask-SocketIO, which uses a non-ASGI system.
Note: deployment of ASGI (and other async) websites on PythonAnywhere is an experimental feature. Some important limitations to know about:
- There is no support for static file mappings.
- There is a very limited web UI for creating and managing async websites. Contact support@pythonanywhere.com if you would like us to enable it for your account.
- We do not guarantee that the command line syntax and the API interface will remain the same.
- We have not worked out the long-term pricing for ASGI sites, which will probably differ from the way we charge for traditional WSGI ones. We're 99.9% certain that there will be a way to host them in a free plan, though!
If you are brave enough to try it, here is a quick guide on how to do it :-)
Prerequisites¶
API token¶
This help page explains how to manage your websites using our pa
command-line
tool rather than the API, but you'll need to generate an API token so that
that tool knows how to connect to PythonAnywhere.
First, you will need an API token. This page will show you how to get that.
Now you can use our command-line tool or our experimental API to deploy your ASGI website. This help page will show you how to use the command-line tool, so you don't need to note down the API token -- now that it has been generated, it's available to any code running inside Bash consoles on PythonAnywhere.
Installing the command-line tools¶
As a first step, start a fresh Bash console, and in there, install the latest version of our command-line tool.
pip install --upgrade pythonanywhere
(As of this writing, it will print out an error about typing-extensions
, but
you can ignore that.)
Running that install will make a new command, pa
available, which we'll be
using later.
Creating a simple test website¶
Now we'll create a simple site that we can deploy. Exactly how you do that depends on the web framework you want to use:
FastHTML¶
Firstly, create a virtual environment with python-fasthtml
installed. In your Bash console:
mkvirtualenv my_venv --python=python3.10
...and then:
pip install python-fasthtml
Next, we'll create a minimal FastHTML site. Create a directory ~/my_fasthtml/
and inside it create a file called main.py
, containing the following code:
from fasthtml.common import FastHTML, H1, Title, P app = FastHTML() rt = app.route @rt("/") def get(): return Title("Hello from FastHTML on PythonAnywhere"), H1("Hello world!"), P("I'm FastHTML on PythonAnywhere!")
That's enough setup! The only other thing you'll need to know to run your site is the command that you will later on provide when creating it; we'll explain the details of this later on, but for now, just note down that it should be this:
/home/YOURUSERNAME/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/YOURUSERNAME/my_fasthtml --uds ${DOMAIN_SOCKET} main:app
...with YOURUSERNAME
replaced by your actual username, but with everything else
exactly as it is.
Now you can move on to creating your website
FastAPI¶
Firstly, create a virtual environment with fastapi
and uvicorn
installed. In your Bash console:
mkvirtualenv my_venv --python=python3.10
...and then:
pip install "uvicorn[standard]" fastapi
Next, we'll create a minimal FastAPI site. Create a directory ~/my_fastapi/
and inside it create a file called main.py
, containing the following code:
from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message":"Hello from FastAPI"}
That's enough setup! The only other thing you'll need to know to run your site is the command that you will later on provide when creating it; we'll explain the details of this later on, but for now, just note down that it should be this:
/home/YOURUSERNAME/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/YOURUSERNAME/my_fastapi --uds ${DOMAIN_SOCKET} main:app
...with YOURUSERNAME
replaced by your actual username, but with everything else
exactly as it is.
Now you can move on to creating your website
Django¶
Firstly, create a virtual environment with django
and uvicorn
installed. In your Bash console:
mkvirtualenv my_venv --python=python3.10
...and then:
pip install "uvicorn[standard]" django
Next, we'll create a minimal Django site. Firstly, in your Bash console, run this:
django-admin startproject asyncdjango
Modify ~/asyncdjango/asyncdjango/urls.py
to look like this:
from django.urls import path from django.http import JsonResponse async def async_view(request): return JsonResponse({'message': 'Hello from async Django!'}) urlpatterns = [ path("", async_view), ]
That's enough setup! The only other thing you'll need to know to run your site is the command that you will later on provide when creating it; we'll explain the details of this later on, but for now, just note down that it should be this:
/home/YOURUSERNAME/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/YOURUSERNAME/asyncdjango --uds ${DOMAIN_SOCKET} asyncdjango.asgi:application
...with YOURUSERNAME
replaced by your actual username, but with everything else
exactly as it is.
Now you can move on to creating your website
Managing your website¶
Creating your website¶
In Bash, to deploy your website to your subdomain -- that is, to
yourusername.pythonanywhere.com
if you're on our US system, or
yourusername.eu.pythonanywhere.com
if you're on the EU system -- just run
the following. You'll need to replace the domain argument as appropriate, and
put the framework-specific command that you noted down earlier inside the single
quotes in place of COMMAND
.
pa website create --domain YOURUSERNAME.pythonanywhere.com --command 'COMMAND'
If everything was successful, you should see something like:
< All done! Your site is now live at YOURUSERNAME.pythonanywhere.com. > \ ~<:>>>>>>>>>
Now, if you go to the website URL defined in domain
you should get something
back from your website -- exactly what, of course, depends on which of the
frameworks you chose agove.
Note: as of this writing, there is a bug that means that you might get a 404 not found page for a few seconds before the site comes up. If you get that, just refresh the page in your browser. We're on the case :-)
You have a working ASGI website hosted on PythonAnywhere! However, this site will not currently appear on the "Web" page inside your PythonAnywhere account; we have a user interface that is a work-in-progress, though, and if you'd like to try that out, drop us a line.
Getting and listing websites¶
You can get a list of ASGI websites from PythonAnywhere with this command:
pa website get
You'll get something like this:
domain name enabled ------------------------------- --------- YOURUSERNAME.pythonanywhere.com True
And you can get the details for one website like this:
pa website get --domain YOURUSERNAME.pythonanywhere.com
...which will display something like this (the command will of course vary based on the framework you're using):
----------- ------------------------------------------------------------------------------------------------------------------------- domain name YOURUSERNAME.pythonanywhere.com enabled True command /home/YOURUSERNAME/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/YOURUSERNAME/my_fastapi --uds ${DOMAIN_SOCKET} main:app ----------- -------------------------------------------------------------------------------------------------------------------------
Using a custom domain for your web app¶
If you are using a custom domain, there will be an extra field called cname
in the output above. This is the CNAME that you can use in your DNS settings
for your web app. For more details on setting up DNS for a custom domain, see:
- How DNS works: a beginner's guide,
- Setting up a custom domain on PythonAnywhere,
- Naked domains,
- Troubleshooting DNS.
Enabling HTTPS for your custom domain webapp¶
You can get a Let's Encrypt certificate for your custom domain using the API too:
pa website create-autorenew-cert --domain YOURCUSTOMDOMAIN
Reloading¶
If you change the code of your website, you'll need to reload it to activate those changes:
pa website reload --domain YOURUSERNAME.pythonanywhere.com
If all goes well, you'll see this:
< Website YOURUSERNAME.pythonanywhere.com has been reloaded! > \ ~<:>>>>>>>>>
...and if you visit the site, you'll see that it's been updated to run your new code.
Delete¶
To delete your website, use this:
pa website delete --domain YOURUSERNAME.pythonanywhere.com
If all goes well, you'll see this:
< Website YOURUSERNAME.pythonanywhere.com has been deleted! > \ ~<:>>>>>>>>>
...and the website will be gone, and replaced with our default "Coming Soon!" page.
Supported UI features¶
Logs¶
You can access the logs -- the ones that were printed out by the detailed
version of the pa website get
command -- from the Files page or from a
console; they're located in /var/log
.
The error log¶
For example, /var/log/YOURUSERNAME.pythonanywhere.com.error.log
.
By default, uvicorn logs its status messages to the standard error stream, so if all is well you'll see something like this:
INFO: Started server process [1] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on unix socket /var/sockets/YOURUSERNAME.pythonanywhere.com/app.sock (Press CTRL+C to quit)
The last line is uvicorn saying that it has successfully started, and is listening for incoming requests on an internal unix domain socket. That socket is internal to our web-hosting system -- you won't be able to see it in a console or on the "Files" page inside PythonAnywhere.
The server log¶
For example, /var/log/YOURUSERNAME.pythonanywhere.com.server.log
.
By default, uvicorn logs incoming requests to the standard output stream, so you'll see something like this:
INFO: - "GET / HTTP/1.1" 200 OK
The access log¶
For example, /var/log/YOURUSERNAME.pythonanywhere.com.access.log
.
This will also show incoming requests, but will be formatted similarly to other PythonAnywhere websites -- for example:
1.2.3.4 - - [17/Oct/2023:13:14:00 +0000] "GET / HTTP/1.1" 200 32 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" "1.2.3.4" response-time=0.286
Technical details¶
If you just want to get an ASGI site up and running, all you need to do is follow the recipe above. However, if you'd like to understand a bit more about what is going on, or to build on these instructions to do more than just ASGI, read on!
As an example, let's use the command that we specified for FastAPI
/home/YOURUSERNAME/.virtualenvs/my_venv/bin/uvicorn --app-dir /home/YOURUSERNAME/my_fastapi --uds ${DOMAIN_SOCKET} main:app
Breaking that down:
-
/home/YOURUSERNAME/.virtualenvs/my_venv/bin/uvicorn
is the path to uvicorn in your virtualenv. Uvicorn is an ASGI container program -- it can run any ASGI-based Python web framework, like FastHTML, FastAPI, or recent versions of Django. -
--app-dir /home/YOURUSERNAME/my_fastapi
is the directory containing your website's code -- in this example, the FastAPI example. -
--uds ${DOMAIN_SOCKET}
is telling uvicorn to listen for incoming requests on a unix domain socket -- the location of that socket is provided by our system in the environment variableDOMAIN_SOCKET
-
main:app
is telling uvicorn, which is looking for code in the specifiedapp-dir
, to load up the ASGI app calledapp
from the filemain.py
. If you're using Django, it will be a little more complicated because of the way Django nests directories.
As we mentioned above, that domain socket (which will be something like
/var/sockets/YOURUSERNAME.pythonanywhere.com/app.sock
) is internal to the
part of our system that serves websites; you won't be able to see
it in a console or on the "Files" page inside PythonAnywhere.
If you want to use an ASGI framework that is not one of the ones we have examples for above, you should be able to get it up and running by:
- Installing the framework into your virtualenv.
- Adjusting the
app-dir
to point to the location of your code. - Changing the last argument to point to the ASGI object that your framework exports.
But in addition, you can even use our new website hosting system to host non-ASGI
servers! It supports any server that is able to listen for incoming requests on a unix domain socket.
You'll just need to work out the appropriate incantation to tell it how to
listen on the socket provided in $DOMAIN_SOCKET
.
The API¶
If you want to control your ASGI site programatically, using Python code rather
than the pa
command-line tool, check out this help page.