this page contain proper account of deploying A Django project on Azure web service manually without CI/CD pipeline.
- Keep this private it contain secret environment variables;
- we are assuming here that you create Django project with best practices
- You Django Project is a Repository of GitHub if not make it
- You install all the python packages required for your project in a virtual environment. If not do it.
- I am assuming here that you already create a virtual environment and install all the package which are required for your Django app to run on the same.
- Install below packages on the same virtual environment
pip install psycopg2
pip install python-dotenv
pip install whitenoise
- Create a deployment.py file on the directory settings.py present
- this file will treated as settings file in deployment environment
- copy and page the below code on that. change if needed.
import os
from .settings import *
from .settings import BASE_DIR
SECRET_KEY = os.environ['SECRET']
ALLOWED_HOSTS = [os.environ['WEBSITE_HOSTNAME']]
CSRF_TRUSTED_ORIGINS = ['https://' + os.environ['WEBSITE_HOSTNAME']]
DEBUG = False
# WhiteNoise configuration
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
'''
# a way to add database connection
conn_str = os.environ['AZURE_POSTGRESQL_CONNECTIONSTRING']
conn_str_params = {pair.split('=')[0]: pair.split('=')[1] for pair in conn_str.split(' ')}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': conn_str_params['dbname'],
'HOST': conn_str_params['host'],
'USER': conn_str_params['user'],
'PASSWORD': conn_str_params['password'],
}
}
'''
- we need to change wsgi.py (present in same dir as settings.py in)
- copy pate the below code on the, don’t forget to change the
project_name
import os
from django.core.wsgi import get_wsgi_application
project_name = "my-project-name"
settings_module = '.deployment' if 'WEBSITE_HOSTNAME' in os.environ else '.settings'
os.environ.setdefault('DJANGO_SETTINGS_MODULE', project_name+settings_module)
application = get_wsgi_application()
- caution: make sure virtual environment activate, and CMD is on the root directory of project (same on which manage.py present)
- run the below command on CMD to create a requirements.txt
pip freeze > requirements.txt
- add a .production file in same directory as manage.py in with below code.
[config]
SCM_DO_BUILD_DURING_DEPLOYMENT=true
- add a .gitignore file in same dir as manage.py in with below code.
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
- with Python as a run-time environment. same version as you build your Django app on local machine
you can use the JSON format for doing it faster
[
{
"name": "WEBSITE_HTTPLOGGING_RETENTION_DAYS",
"value": "1",
"slotSetting": false
},
]
-
Generate SSH-key with Azure App Service SSH
ssh-keygen -t rsa -b 4096 -C "[email protected]"
cat ~/.ssh/id-rsa.pub
-
Set this SSH-key in GitHub with GUI
💡 ‣ | https://github.com/settings/keysabove is the direct link for that same site, better to save with the name of App-service
-
Verify Connection
ssh -T [email protected]
-
Install git in App service
apt install git
-
clone the repo
cd ~/home/site/wwwroot/ # more to deployment directory git clone <ssh-url-of-repo> # remember ssh url and http url
-
Build it
here the the build command either you can do it by yourself or just copy past below instruction in chat-gpt by putting your
repo-name
andgithub-username
on top line and GPT will do give a handy command file for you that you can copy past directly on app-service SSH# my repo name is [pur-repo-name-here] my github username is [github-username] # re write all these command for me so that I can copy page these in my azure app service cli directly cd ~/home/site/wwwroot/ # more to deployment directory cd <repo-name> # move into the project git checkout <branch-name> # switch to branch you want to deploy cd .. # go back python -m venv antenv # create python virtual environment with name antenv source antenv/bin/activate # activate the virtual environment pip install -r <repo-name>/requirements.txt # install the requirement of your django project pip install gunicorn # might be gunicorn not in the requirements cd <repo-name> # again to into the repo directory py manage.py migrate # migrate the migrations py manage.py collectstatic --noinput # collect all the static files
-
Open two window of app-service SSH and navigate to repo directory on both.
cd ~/home/site/wwwroot/my-repo/ # same file where manage.py is present
-
test server is running properly with | python manage.py runserver
# on SSH window 1 py manage.py runserver 1010 # run the runsever on port 1010 as might be 8000 already busy # TIP: you can also see in this ouput which setting is working s dettings.py or deployment.py # on SSH window 2 while server is continuously running on window 1 curl <http://localhost:1010/> # lisen to the loclhost port 1010 # if it give no output --> good test passed # if it give some html context which show erro code 400 --> test failed something is wrong # if it give some html context which do not contain error --> text passed # now u can stop the server at window 1 by crt+C
-
test by running
gunicorn
server# on SSH window 1 gunicorn --bind 0.0.0.0:1010 sharktodo2.wsgi:application --access-logfile - --error-logfile - # run the runsever on port 1010 as might be 8000 already busy # on SSH window 2 while server is continuously running on window 1 curl <http://localhost:1010/> # lisen to the loclhost port 1010 # if it give no output --> good test passed # if it give some html context which show erro code 400 --> test failed something is wrong # if it give some html context which do not contain error --> text passed # now u can stop the server at window 1 by crt+C
navigate to app service configuration and set give start-up command there and save it.
just wait for max 5 min and visit your app service URL your Django app will be live there
source antenv/bing/activate
cd [your-repo-name]
gunicorn --bind 0.0.0.0:8000 sharktodo2.wsgi:application --access-logfile - --error-logfile -
- you can check Log of of from the app-service sidebar Log Stream
- and even you can turn more detailed log from app-service side-bar app-service-logs
- have doubt my deployment.py settings are running or not
- just run python manage.py runserver from the ssh it will show which setting are running