It’s been a while since my last post. I have been developing the flashcard web app (vocaBull (2); vb2).
I successfully deployed vb2 in PythonAnywhere (PA) at https://achiwa912.pythonanywhere.com. Note that it’s still alpha quality with debug info shown. In this post, I write what I did for the deployment for the record.
Prep on local MacBook
Update required Python versions
I use python 3.14 for the development on mac. As PA supports up to 3.13, I needed to change the python version for the project.
- Change required python version (was >=3.14) in vb2/pyproject.toml
requires-python = ">=3.13"
Build frontend
As setuptools invoked by uv don’t support .org for README, delete this line from vb2/pyproject.toml
readme = "README.org" # delete this line. Or, replace with .md/.rst/.txt
- uv lock (and git commit)
uv lock
- build. .js and .css are created under vb2/fe/dist
pnpm build
- commit vb2/fe/dist
- remove dist from .gitignore (I have .gitignore at /vb2 as well as /vb2/fe)
Serve frontend via Flask
For dev, I run pnpm dev for dev webserver. I needed to update api.py to serve static files I just built. I use an env variable SERVE_FRONTEND to distinguish if it’s running on mac or in PA.
- Add at the end of api.py:
# ---------------------------------------------------------------------------
# Serve the built Vue frontend (production only)
# ---------------------------------------------------------------------------
import os as _os
from flask import send_from_directory
if _os.environ.get("SERVE_FRONTEND") == "1":
FRONTEND_DIST = _os.path.join(
_os.path.dirname(_os.path.dirname(_os.path.abspath(__file__))),
"fe",
"dist",
)
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def serve_frontend(path):
full = _os.path.join(FRONTEND_DIST, path)
if path and _os.path.exists(full):
return send_from_directory(FRONTEND_DIST, path)
return send_from_directory(FRONTEND_DIST, "index.html")
Google Cloud Console
Google accepts auth only from pre-configured URLs. To avoid being rejected by Google,
- Login to GCC > APIs & Services > Credentials > vocabull > add https://achiwa912.pythonanywhere.com
Deploy vb2 on PythonAnywhere (PA)
Update PA system image
I was using haggis system image which supports up to python 3.10.
https://help.pythonanywhere.com/pages/ChangingSystemImage
- Go to Account > System Image
- Change current system image to
innit - Change all default python version to use 3.13
Wipe all and start fresh
- Open console and wipe everything
rm -rf ~/*
rm -rf ~/.*
rm -rf /tmp/*
- Close console and start a new one
- Should use python 3.13. Confirm:
python -V
- Should use python 3.13. Confirm:
Create environment
- Create virtual env and git clone vb2 from the github repo
cd ~/
mkvirtualenv vb2-venv
git clone https://github.com/achiwa912/vb2.git
- Edit vb2/.python-version
3.13 # from 3.14
- Install libraries
- The UV_PROJECT_ENVIRONMENT var was the key — uv sync otherwise wants to create .venv
--python 3.13option might not be needed
UV_PROJECT_ENVIRONMENT=/home/achiwa912/.virtualenvs/vb2-venv uv sync --no-install-project --python 3.13
- Note:
uv pip install -e .didn’t work because setuptools can’t decide between be/ and fe/.uv pip sync uv.lockdidn’t work as it expectsrequirements.txt, notuv.lock.
Create a new webapp
- delete achiwa912.pythonanywhere.com at Web tab
- add a new web app > Manual configuration (note: NOT Flask)
- Python 3.13
- Source code: /home/achiwa912/vb2
- Working directory: /home/achiwa912/vb2
- Virtualenv:
/home/achiwa912/.virtualenvs/vb2-venv
- Open console and edit /var/www/achiwa912_pythonanywhere_com_wsgi.py
import sys
import os
from dotenv import load_dotenv
project_folder = os.path.expanduser('~/vb2')
load_dotenv(os.path.join(project_folder, '.env'))
path = '/home/achiwa912/vb2'
if path not in sys.path:
sys.path.insert(0, path)
os.chdir(path)
from be.api import app as application
- vim .env at ~/vb2
export SERVE_FRONTEND=1
export CORS_ORIGINS=http://localhost:5173,https://achiwa912.pythonanywhere.com
export JWT_SECRET_KEY=<snip>
export GGL_CLIENT_ID=<snip>
- For bash console (optional?)
echo 'set -a; source ~/vb2/.env; set +a' >> ~/.virtualenvs/vb2-venv/bin/postactivate
- From Web tab, reload achiwa912.pythonanywhere.com
Frontend auth fix
If I accessed https://achiwa912.pythonanywhere.com, I saw http error 422 on /books. Looking into it, the cause was that the Authorization header was set to null. To fix the issue, I added onRequest middleware in fe/src/api/client.ts and removed per-call headers.
After the fix, it works beautifully.