{"id":16415946,"url":"https://github.com/harikvpy/deploy-django","last_synced_at":"2025-10-07T13:05:19.811Z","repository":{"id":74462046,"uuid":"70661713","full_name":"harikvpy/deploy-django","owner":"harikvpy","description":"A bash script to deploy a django project for production sites.","archived":false,"fork":false,"pushed_at":"2022-04-29T07:43:58.000Z","size":50,"stargazers_count":97,"open_issues_count":0,"forks_count":37,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-01T23:22:29.379Z","etag":null,"topics":["deployment","django","django-rest-framework","python","python3","ubuntu"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/harikvpy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-12T04:11:21.000Z","updated_at":"2025-01-15T21:33:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"8a187a5d-4728-4b2b-adce-44efafcfc71d","html_url":"https://github.com/harikvpy/deploy-django","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/harikvpy/deploy-django","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harikvpy%2Fdeploy-django","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harikvpy%2Fdeploy-django/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harikvpy%2Fdeploy-django/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harikvpy%2Fdeploy-django/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/harikvpy","download_url":"https://codeload.github.com/harikvpy/deploy-django/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harikvpy%2Fdeploy-django/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278778974,"owners_count":26044259,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deployment","django","django-rest-framework","python","python3","ubuntu"],"created_at":"2024-10-11T07:07:53.532Z","updated_at":"2025-10-07T13:05:19.777Z","avatar_url":"https://github.com/harikvpy.png","language":"Shell","funding_links":["https://www.buymeacoffee.com/harikvpy"],"categories":[],"sub_categories":[],"readme":"[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/harikvpy)\n\n# deploy-django\nA bash script to deploy a django project for production sites. The script sets\nup the environment under which the django project can be run safely. The\nenvironment will have the following characterstics:\n\n* Designed to be run using Gunicorn/WSGI and as an app under NGINX.\n* Each site will be run in a dedicated automation user account sandbox.\n* A new PostgreSQL database with the same name as the project specified\n  in command line that can be used by Django.\n* Python virtualenv setup with basic packages such as pip and django installed.\n* Supervisor, the python based daemon control process installed and\n  configured with the necessary conf file to control the WSGI process.\n* An script to autostart supervisor and control it like other Ubuntu services.\n\n# Usage\nThe primary end-user facing components of the package are the two scripts:-\n\n* `install_os_prereq.sh`\n* `deploy_django_project.sh`\n\nThe names ought to be self explanatory.\n\nIn any case, the first script ensures that the necessary packages are installed\nin the OS. Run this first when deploying a django project to a fresh Ubuntu\nimage.\n\nThe second script creates the automation account, virtual environment,\nPostgreSQL DB \u0026 and sets up the assortment of scripts that make up the website\ndeployment.\n\n`install_os_prereq.sh` needs to be run only once per machine, typically after\na fresh OS image installation. Thereafter `deploy_django_project.sh` can be run\nas many times as necessary, once for each domain that you want to support on\nthe same machine (using HTTP virtual hosts).\n\n\u003e The old command `create_django_project_run_env.sh` is essentially a wrapper\n\u003e that calls the above two scripts in sequence. Unless you have a specific\n\u003e reason (I can't think of any), it's best that you don't use this script at\n\u003e all. Instead use the new scripts `install_os_prereq.sh` and\n\u003e `deploy_django_project.sh`.\n\nUse the commands as follows:\n```\ninstall_os_prereq.sh [\u003cpython-version\u003e]\ndeploy_django_project.sh \u003cproject\u003e \u003cdomain\u003e [\u003cpython-version\u003e]\n```\nwhere:\n\n`\u003cproject\u003e` is the name of the parent project you use to refer to the\nsolution. This should be a single word without space or other special charactes.\nA new user account with this name will be created under group `webapps` and\nthe django project will be served from this account's home folder\n`/webapps/\u003cproject\u003e_project`. If group `webapps` does not exist, it will\nbe created.\n\n`\u003cdomain\u003e` is the domain name where the website is to be to be deployed.\nSpecify this without the `www` prefix. Appropriate NGINX configuration files\nwill be generated to direct requets to both `\u003cdomain\u003e` and\n`www.\u003cdomain\u003e` to the django app.\n\n`\u003cpython-version\u003e` is either `2` or `3`, which is the python version that you\nwish to use for the project. In most cases this can be omitted as it defaults\nto `3`.\n\nFor example, for deploying the domain example.com, use the following command:\n\n```\n$ install_os_prereq.sh\n$ deploy_django_project.sh example example.com\n```\nNote that in both the above commands the default Python version of `3` is used.\n\nThis will create a new user account `example` under group `webapps` with home\nfolder set to `/webapps/example_project/`. Under this folder, it will create a\npython virtual environment and a gunicorn startup script, that will be auto\nstarted using the Supervisor process control system. Ngix configuration will be\nupdated such that requests to domain example.com (and wwww.example.com) will be\nproxied to this gunicon WSGI instance. A placeholder Django app, aptly named\n`\u003cproject\u003e` will also be created under the home folder which will serve as the\nthe WSGI endpoint.\n\n# Background\nA production Django app is deployed using the WSGI proxy mechanism which\nserves requests proxied from an HTTP server such as NGINX or Apache. Here the\nHTTP server does little more than forwarding the incoming requests to the\nconfigured WSGI backend application server and forward the received response\nfrom the appserver to the client. The HTTP server will be configured such\nthat for specific domain name(s), a specific WSGI app server instance will be\nused. For Django apps, the recommended HTTP server and WSGI app servers are\nNGINX and Gunicorn respectively.\n\nSince deploying a production web app involves multiple components and each of\nthem with their own configuration, it's imperative that all these varied steps\nare either documented or captured in the form of script files such that these\ncan be replicated across multiple server instances. Even for the most simple\nweb application that uses a single server instance, a production site requires\na staging server where the code needs to be deployed and tested for runtime\nand deployment issues before launching it live. And for sites expecting medium\nto heavy traffic and load, the code would have be deployed on multiple servers\nwith the HTTP server deployed as a load balancer or a dedicated load balancer\ndistributing the HTTP request load equally across multiple application servers.\nTherefore the need for consistent configuration of multiple servers cannot be\noveremphasized.\n\nAn even better solution would be standardizing the deployment characteristics\nof a Django web application such that multiple Django applications, serving\nmultiple sites, all are deployed in a certain fixed configuration. This would\nmake troubleshooting and subsequent fixing of any deployment issues easy as\nall sites retain the same characteristics.\n\nThis script is an attempt to achieve this deployment standardization for all\nDjango apps.\n\n# Assumptions\n\n* Script is written to work with Ubuntu Linux 14.04, though it should work fine\n  on Ubuntu versions \u003e= 12.04. Script does install the prerequisite Linux\n  packages if they are not installed and therefore a vanilla OS installation\n  is all that is necessary.\n* PostgreSQL is used as the database backend. PostgreSQL is considered the best\n  DB backend for Django apps and provides more sophisticated RDBMS features than\n  MySQL.\n* As already mentioned HTTP server is provided by NGNIX and WSGI is served by\n  Gunicorn. NGINX and Gunicorn are considered the best match for Django apps.\n* Supervisor process control system is managed to Gunicorn appserver processes.\n  Using supervisor provides automatic restart of the Gunicorn appserver daemon,\n  should it crash for some reason, making the overall deployment that much more\n  robust.\n* The app server is served using python runtime from a dedicated virtual\n  environment and therefore the system-wide python distribution is not touched.\n\n# Details\nThe sequence of steps taken by the script can be summed up as:\n## OS Packages\nAs part of the installation, the following OS packages are installed:\n* git\n* build-essential\n* nginx\n* postgresql\n* libpq-dev\n* python-dev|python3-dev\n* python-pip|python3-pip\n\nNote that the package `python-pip` \u0026 `python3-pip` is a python package, though\nit is installed from the OS package distribution mechanism.\n\nAfter successful completion of the above, necessary global python packages\nare installed. These are:\n* virtualenv\n* supervisor\nThese are installed using Python Package Installer, which itself installed in\nthe previous step(through `python-pip`).\n\n## User/Group\nA dedicated user account is created for the app server. This helps isolate\nthe app server's run environment from other normal user accounts which are\ntypically used to login to the machine to do management tasks. This is an\nautomation account and disabled for interactive login. This user account name\ndefaults the `\u003cproject\u003e` argument of the command line and is made a member of\ngroup `webapps`. If this group does not exist, it will be created.\n\nHome folder for this account will be set to `/webapps/\u003cproject\u003e_project`.\n\n## Runtime environment\nPost user/group creation, the runtime evironment for the app is created. First\nthe python virtual environment is created. This is created in the home folder\nof the dedicated automation user account. Therefore `python` and related\nbinaries will be installed to `~/bin` folder and python packages will be\ninstalled at `~/local/lib/python2.x` or `~/local/lib/python3.x`.\n\nThe following packages will be installed to the dedicated python virtual\nenvironment just created:\n\n* django\n* psycopg2\n* gunicorn\n* setproctitle\n\n## Runtime scripts\nThe script then generates two bash scripts that will be used to start the app\nserver. The script is split into two files such that it can be used for\ninteractive shell for manual interaction with the Django app server. These\nscripts are:\n* prepare_env.sh\n* gunicorn_start.sh\n\nThe former is an environment script and is to be sourced from the interactive\nshell whereas the latter is the master script that is used to the start Gunicorn\napp server (Supervisor will be configured to start the app server through this\nscript).\n\nSo if manual interaction with the production site is desired, one may sudo into\nthe `\u003cproject\u003e` user account and source it as:\n\n```\n$ sudo -u \u003cproject\u003e -i\n$ source ./prepare_env.sh\n```\n\n## Database\nA PostgreSQL database, with the same name as `\u003cproject\u003e` will be created for\nuse by the Django app. A dedicated PostgreSQL role with the same name will\nalso be created. This role is configured with a random password and this\npassword is stored in `~/.django_db_password`.\n\n## Nginx Configuration\nA Nginx conf file for the requested domain will be created in\n`/etc/nginx/sites-available` and it will be enabled by creating the necessary\nsoft link in `/etc/nginx/sites-enabled`. This configuration will be setup such\nall requests to the domain (specified in the command line argument) will be\nproxied to the Gunicorn server started through the script created earlier.\n\n## Setup supervisor\nSupervisor installation does not create its own configuration file,\n`/etc/supervisord.conf`. Also Supervisor installation does not create the\nnecessary `init.d` script to start it automatically and manage it interactively.\nThis script addresses both by creating the necessary files for this --\n`/etc/supervisord.conf` and `/etc/init.d/supervisord`, a script to manage it\nusing the Ubuntu standard `service \u003cdaemon\u003e {start|stop}` commands.\n\nThe script will also create `/etc/supervisor/\u003cproject\u003e/conf` file which will\ncontain the configuration for the Gunicorn app server.\n\n## Placeholder Django app\nA placeholder Django app will be created in\n`/webapps/\u003cproject\u003e_project/\u003cproject\u003e`. This placeholder app can be replaced\nwith the real production code.\n\n## Other Details\n### Django secret key\nDjango applications generated using its admin command, will put the secret key\nin the generated settings file. Since the Django source is shared between\ndifferent developers and since the code is typically stored in an online\nrepository, this key gets shared across different machines and usere. Therefore\nproduction sites should not use this embedded key and instead should use its\nown key. To automate this the script will generate a random string which is\nstored in `~/.django_secret_key`.\n\n### Environment variables\nBoth the secret key and the database role password (stored in\n`~/.django_secret_key` and `~/.django_db_password`) is made available to\nthe Django app through the environment variables `SECRET_KEY` and\n`DB_PASSWORD` respectively. These variables will be set through the script\n`~/prepare_env.sh`.\n\nAdditionally, the settings file to be used with the Django app is set\nthrough the environment variable `DJANGO_SETTINGS_MODULE`.\n\nProviding these three environment variables, allows the Django app to use\ndifferent values for these three Django app parameters in production\nenvironment than what is used in development.\n\n# Notes\nThe script, `~/gunicorn_start.sh` is the only connection between the Gunicorn\nconfiguration and the Django app server. So as long as running this script\nresults in a valid app server instance, the rest of the system will remain\nof the expected integrity. So if the Django app being deployed requires\ndifferent configuration, any requisite changes can be made from this file.\n\n`~/prepare_env.sh` is sourced from this file to setup the environment. So this\nfile is also available for further tweaking to suit the deployed app's\nruntime environment.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharikvpy%2Fdeploy-django","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharikvpy%2Fdeploy-django","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharikvpy%2Fdeploy-django/lists"}