Deploying our project has become really essential. No matter if it's a simple portfolio site or a quick startup idea we want to validate, If we don't push to the web, We do not get any feedback and possibly miss out on the impact the project could have.
In this tutorial, we will deploy our fastapi application to a Linux server. I could have gone with Heroku, railways, etc., but these PASS hide a lot of abstraction and minimize the learning opportunity. Instead, let's do it the hard way! Feel free to use, any platform for getting a Linux machine, e.g. AWS, GCP, Digitalocean, Linode, etc. I have bought a really small server from Digitalocean for this purpose.
We should not work with root users directly, let's follow the best practices and create a new user named johnwick.
root@fastapixcelery:~# adduser johnwick
Set a password and specify the name and other optional details if you want. At later stage, we will need to run several commands using sudo, so we need to add johnwick to the sudoers group.
usermod -aG sudo johnwick
Before logging out, let's prepare ourselves, to be able to ssh via this new user. If you don't have a ssh-key in your local computer, create one using the command ssh-keygen just go with the default options if you feel confused. Use cat ~/.ssh/id_rsa.pub to display the value of your public key. This needs to be put into remote server.
#login as johnwick
root@fastapixcelery:~# su - johnwick
johnwick@fastapixcelery:~$
johnwick@fastapixcelery:~$ mkdir .ssh
johnwick@fastapixcelery:~$ cd .ssh
johnwick@fastapixcelery:~/.ssh$ touch authorized_keys
johnwick@fastapixcelery:~/.ssh$ nano authorized_keys
#paste your public ssh key i.e. value of id_rsa.pub and save the file
johnwick@fastapixcelery:~/.ssh$ sudo systemctl restart ssh
[sudo] password for johnwick:
Now, we should be able to enter the remote server with ssh johnwick@ip_of_server. Additionally, let's set up a basic firewall and allow only SSH connections to our server.
johnwick@fastapixcelery:~# sudo ufw app list
Available applications:
OpenSSH
johnwick@fastapixcelery:~# sudo ufw allow OpenSSH
Rules updated
Rules updated (v6)
johnwick@fastapixcelery:~# sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
johnwick@fastapixcelery:~# sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
For additional security, I would recommend disabling password authentication and using only the ssh key for authentication to avoid brute-force login attacks on our server. We did not use a database in our demo fastapi celery application, however, in the real world, you might be using a database e.g. Postgres. To set up a database, follow this guide.
Now, we should ssh into our remote server using johnwick user.
First of all, we need to add gunicorn in our requirements.txt. Gunicorn will have uvicorn workers that will serve our application.
uvicorn==0.21.1
fastapi==0.95.0
redis==4.5.4
celery==5.2.7
python-dotenv==1.0.0
flower==1.2.0
watchdog==3.0.0
gunicorn==20.1.0
I would also suggest to add one more route, the home/base route which will be useful to validate if fastapi server is working properly or not.
#main.py
# .. old content here
@app.get("/")
def home():
return {"ping":"pong!!"}
We need to push our code in Github/GitLab. Make sure, you put logs, .env, and env in the .gitignore file. Once we have done this, we can enter our server by typing ssh [email protected]. Once we are inside, we can create a directory of our choice and cd into it. Finally, we do a git clone to bring our repo to the production server. Make sure to create a logs directory and .env file.
johnwick@fastapixcelery:~# pwd
/home/johnwick
johnwick@fastapixcelery:~# mkdir project
johnwick@fastapixcelery:~# cd project/
johnwick@fastapixcelery:~/project# git clone https://your_git_repo_url
johnwick@fastapixcelery:~/project# mkdir logs
johnwick@fastapixcelery:~/project# touch .env
We need to create a virtual environment, however, our Linux version does not have venv preinstalled. Before installing venv, you must execute sudo apt update. Then, we will need to run sudo apt install python3.10-venv once env is ready.
We might need to install pip via sudo apt install python3-pip if pip is unrecognized.
We can activate the virtual environment by source ./env/bin/activate . Once we have our env activated, we can install the requirements by pip install -r requirements.txt
At this point, you can start uvicorn in one terminal via uvicorn main:app in one terminal and send a curl request from another terminal.
root@fastapixcelery:~# curl http://127.0.0.1:8000
{"ping":"pong!!"}
You should see {"ping":"pong!!"}. This means we are proceeding in the right direction.
Brige the gap between Tutorial hell and Industry. We want to bring in the culture of Clean Code, Test Driven Development.
We know, we might make it hard for you but definitely worth the efforts.
© Copyright 2022-23 Team FastAPITutorial