Reputation: 478
I've developed a FastAPI app that will act as a wrapper that receives SMS requests and call the SMS API to send SMS and now I'm ready to deploy it. This is the code:
import logging
import uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from fastapi.middleware.trustedhost import TrustedHostMiddleware
import verifier
logging.basicConfig(
format='%(asctime)s - %(funcName)s - %(levelname)s - %(message)s',
level=logging.INFO
)
# get logger
logger = logging.getLogger(__name__)
bot_verifier = None
class DataForBot(BaseModel):
number: str
msg_txt: str
def get_application():
app = FastAPI(title='bot_wrapper', version="1.0.0")
return app
app = get_application()
@app.on_event("startup")
async def startup_event():
global bot_verifier
try:
bot_verifier = await verifier.Verifier.create()
except Exception as e:
logger.error(f"exception occured during bot creation -- {e}", exc_info=True)
@app.post('/telegram_sender/')
async def send_telegram_msg(data_for_bot: DataForBot):
global bot_verifier
if not bot_verifier:
bot_verifier = await verifier.Verifier.create()
else:
dict_data = data_for_bot.dict()
try:
if await bot_verifier.send_via_telegram(dict_data):
return {'status': "success", 'data': data_for_bot}
else:
raise HTTPException(status_code=404, detail="unable to send via telegram, perhaps user has not started the bot")
except Exception as e:
logger.error(f"{e}", exc_info=True)
raise HTTPException(status_code=500, detail="Something went wrong, please contact server admin")
I want to deploy it on apache, as it is the only thing I can get my hand onto in my country. I'm using Python 3.8.9 with FastAPI 0.65.2 and apache/2.4.29, but for the life of me I can't get it to work. I've written an apache conf file and enabled that as such:
<VirtualHost *:80>
ServerName gargarsa.sms.local
ServerAdmin webmaster@localhost
ServerAlias gargarsa.sms.local
DocumentRoot /var/www/verify_bot_api/
ServerAlias gargarsa.sms.local
<Directory /var/www/verify_bot_api/src/app/>
Order deny,allow
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/gargarsa.sms.local-error.log
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/gargarsa.sms.local-access.log combined
</VirtualHost>
but no avail.
I tried running gunicorn via a screen session but I couldn't access it either.
I tried running it programmatically as such but no avail:
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
I understand this is a very broad way to ask, but I'm truly stumped.
How do I run an API built using FastAPI on Apache2?
Thank you for your assistance.
Upvotes: 9
Views: 16725
Reputation: 520
Forget everything. Here is a simple guide.
Assuming there is your virtual env called venv
. And we have apache installed in place on linux.
Restart Apache for a fresh start
sudo systemctl restart apache2
You need Uvicorn to keep running in the background. Set up a Systemd service to manage your FastAPI app:
Create a new service file:
sudo nano /etc/systemd/system/fastapi.service
Add the following configuration (adjust paths as necessary):
[Unit]
Description=FastAPI hosted application
After=network.target
[Service]
# User and group for running the service
User=root
Group=root
# Working directory of your FastAPI project
WorkingDirectory=/path/to/fastapi/app
# Activate the virtual environment
Environment="PATH=/path/to/venv/bin"
# Start the FastAPI application with Uvicorn
ExecStart=/path/to/venv/bin/uvicorn api:app --host 0.0.0.0 --port 1234 --workers 9
# Graceful reload and stop commands
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
# Restart policy and security
Restart=always
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Reload Systemd and start your service:
sudo systemctl daemon-reload
sudo systemctl start fastapi.service
sudo systemctl enable fastapi.service
Verify that Uvicorn is running:
sudo systemctl status fastapi.service
Create a new Apache configuration file for your FastAPI app:
sudo nano /etc/apache2/sites-available/fastapi.conf
Add the following content:
<VirtualHost *:80>
ServerName yourdomain.com
ServerAdmin [email protected]
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
ErrorLog ${APACHE_LOG_DIR}/fastapi-error.log
CustomLog ${APACHE_LOG_DIR}/fastapi-access.log combined
</VirtualHost>
yourdomain.com
with your domain name (or leave as localhost
for testing).Enable the site and reload Apache:
sudo a2ensite fastapi.conf
sudo systemctl reload apache2
http://yourdomain.com
or http://127.0.0.1
).This is more than enough!!
Upvotes: 0
Reputation: 16
It should be possible using ASGIMiddleware that converts ASGI app to WSGI app e.g. with a2wsgi.
Please see the example at https://github.com/fnep/example_fastapi_behind_apache_using_wsgi
Upvotes: 0
Reputation: 235
WSGI servers is not compatible with FastAPI, FastAPI only runs in ASGI server, gunicorn and all the other WSGI servers just implements PEP Standards with ASGI workers in depth they still work as ASGI with the workers.
Upvotes: 0
Reputation: 478
Just incase anybody else stumbles on here, this is what I did and this is how it worked for me. This came about b/c there was not a lot of information on the web -- that I could find -- in regards to deploying fastapi on linux -- specifically ubuntu 18.04.4 -- with apache2 and no other things. When I say no other thing, I mean docker, caddy, or whatever of the sorts.
The usual things must be done before hand, these are:
Functioning Sample apache conf file:
<VirtualHost *:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerName server-name
ServerAdmin webmaster@localhost
ServerAlias server-alias
#DocumentRoot /document/root/
<Proxy *>
AuthType none
AuthBasicAuthoritative Off
SetEnv proxy-chain-auth On
Order allow,deny
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:port/
ProxyPassReverse / http://127.0.0.1:port/
#ProxyPass /api http://127.0.0.1:port/api
#ProxyPassReverse /api http://127.0.0.1:port/api
<Directory /document/root/>
Order deny,allow
Allow from all
</Directory>
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/server-error.log
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/server-access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
To run the actual api:
gunicorn api:app -w 1 -k uvicorn.workers.UvicornWorker -b "127.0.0.1:port"
Edit: I have not placed any security mechanism at all here
Upvotes: 17