Last time we set up a Django Project using Cookiecutter, managed the application environment via Docker, and then deployed the app to Digital Ocean. In this tutorial, we’ll shift away from Docker and detail a development to deployment workflow of a Cookiecutter-Django Project on Fedora 23.
Development
Install cookiecutter globally and then generate a bootstrapped Django project:
1 2 |
|
This command runs cookiecutter with the cookiecutter-django repo, allowing us to enter project-specific details. (We named the project and the repo django_cookiecutter_fedora.)
NOTE: Check out the Local Setup section from the previous post for more information on this command as well as the generated project structure.
Before we can start our Django Project, we are still left with few steps…
Database Setup
First, we need to set up Postgres since cookiecutter-django uses it as its default database (see django_cookiecutter_fedora/config/settings/common.py for more info). Follow the steps to set up a Postgres database server, from any good resource on the Internet or just scroll down to the Deployment Section for setting it up on Fedora.
NOTE: If you’re on a Mac, check out Postgres.app.
Once the Postgres server is running, create a new database from psql that shares the same name as your project name:
1 2 |
|
NOTE: There may be some variation in the above command for creating a database based upon your version of Postgres. You can check for the correct command in Postgres’ latest documentation found here.
Dependency Setup
Next, in order to get your Django Project in a state ready for development, navigate to the root directory, create/activate a virtual environment, and then install the dependencies:
1 2 3 4 |
|
Sanity Check
Apply the migrations and then run the local development server:
1 2 3 |
|
Ensure all is well by navigating to http://localhost:8000/ in your browser to view the Project quick start page. Once done, kill the development server, initialize a new Git repo, commit, and PUSH to Github.
Deployment
With the Project setup and running locally, we can now move on to deployment where we will utilize the following tools:
Fedora 23 Setup
Set up a quick Digital Ocean droplet, making sure to use a Fedora 23 image. For help, follow this tutorial. Make sure you set up an SSH key for secure login.
Now let’s update our server. SSH into the server as root, and then fire the update process:
1 2 |
|
Non-Root User
Next, let’s set up a non-root user so that applications are not run under administrative privileges, which makes the system more secure.
As a root user, follow these commands to set up a non-root user:
1 2 3 4 5 6 |
|
In the above snippet we created the new, non-root user user then specified a password for said user. We now need to add this user to the administrative group so that they can run commands that require admin privileges with sudo
:
1
|
|
Exit from the server and log back in again as the non-root user. Did you notice that the shell prompt changed from a #
(pound-sign) to $
(dollar-sign)? This indicates that we are logged in as a non-root user.
Required Packages
While logged in as the non-root user, download and install the following packages:
Note: Below we are giving our non-root user root rights (recommended!). If by any chance you wish to not give the non-root user root rights explicitly, you will have to prepend
sudo
keyword with every command you execute in the terminal.
1 2 |
|
Postgres Setup
With the dependencies downloaded and installed, we just need to set up our Postgres server and create a database.
Initialize Postgres and then manually start the server:
1 2 |
|
Then log in to the Postgres server by switching (su
) to the postgres
user:
1 2 3 |
|
Now create a Postgres user and database required for our project, making sure that the username matches the name of the non-root user:
1 2 3 4 5 6 |
|
NOTE: If you need help, please follow the official guide for setting up Postgres on Fedora.
Exit psql and return to your non-root user’s shell session:
1 2 |
|
When you exit from the postgres session, you will return back to your non-root user prompt. [username@django-cookiecutter-deploy ~]#
.
Note: Did you notice the
#
sign at the prompt? This is now appearing because we gave our non-root user the root rights before starting off with setting up our server.
Configure Postgres so that it starts when the server boots/reboots:
1 2 |
|
Project Setup
Clone the project structure from your GitHub repo to the /opt directory:
1
|
|
NOTE: Want to use the repo associated with this tutorial? Simply run:
sudo git clone https://github.com/realpython/django_cookiecutter_fedora /opt/django_cookiecutter_fedora
Dependency Setup
Next, in order to get your Django Project in a state ready for deployment, create and active a virtualenv inside your project’s root directory:
1 2 3 |
|
Before activating the virtualenv, give the current, non-root user admin rights (if not given):
1 2 |
|
Unlike with the set up of the development environment from above, before installing the dependencies we need to install all of Pillow’s external libraries. Check out this resource for more info.
1 2 |
|
Next, we need to install one more package in order to ensure that we do not get conflicts while installing dependencies in our virtualenv.
1
|
|
Then run:
1
|
|
Again, this will install all the base, local, and production requirements. This is just for a quick sanity check to ensure all is working. Since this is technically the production environment, we will change the environment shortly.
NOTE: Deactivate the virtualenv. Now if you issue an exit command – e.g.,
exit
– the non-root user will no longer have root rights. Notice the change in prompt. That said, the user can still activate the virtualenv. Try it!
Sanity Check (take 2)
Apply all the migrations:
1 2 |
|
Now run the server:
1
|
|
To ensure things are working fine, just visit the server’s IP address in your browser – e.g., <ip-address or hostname>:8000.
Gunicorn Setup
Before setting up Gunicorn, we need to make some changes to the production settings, in the /config/settings/production.py module.
Take a look at the production settings here, which are the minimal settings needed for deploying our Django Project to a production server.
To update these, open the file in VI:
1
|
|
First, select all and delete:
1
|
|
And then copy the new settings and paste them into the now empty file by entering INSERT mode and then pasting. Make sure to update the ALLOWED_HOSTS
variable as well (very, very important!) with your server’s IP address or hostname. Exit INSERT mode and then save and exit:
1
|
|
Once done, we need to add some environment variables to the .bashrc file, since the majority of the config settings come from environment variables within the production.py file.
Again, use VI to edit this file:
1
|
|
Enter INSERT mode and add the following:
1 2 3 4 5 6 |
|
Two things to note:
- Notice how we updated the
DJANGO_SETTINGS_MODULE
variable to use the production settings. - It’s a good practice to change your
DJANGO_SECRET_KEY
to a more complex string. Do this now if you want.
Again, exit INSERT mode, and then save and exit VI.
Now just reload the .bashrc file:
1
|
|
Ready to test?! Inside the root directory, with the virtualenv activated, execute the gunicorn server:
1
|
|
This will make our web application, again, serve on <ip-address or hostname>:8000.
Keep in mind that as soon as we log out of our server this command will stop and hence we would no longer be able to serve our web app. So, we have to make our gunicorn server execute as a service so that it can be started, stopped, and monitored.
Nginx Config
Follow these steps for adding a configuration file for making our Django Project serve via Nginx:
1 2 |
|
Add the following, making sure to update the server
, server_name
, and location
for project root:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Save and exit VI, and then restart the Nginx server:
1
|
|
That’s it!
Gunicorn Start Script
Now let’s create a Gunicorn start script which will run as an executable, making our bootstrapped Django web application run via the Gunicorn server, routed through Nginx.
Within the project root, run:
1 2 3 |
|
The contents of the gunicorn_start script can be found here. It is divided into 3 significant parts, which are, for the most part, self-explanatory. For any questions, please comment below.
NOTE: Make sure the
USER
andGROUP
variables match the same user and group for the non-root user.
Paste the contents into VI, and then save and exit.
Finally, let’s make it executable:
1
|
|
Start the server:
1
|
|
Once again visit the your server’s ip address in the browser and you will see your Django web app running!
Did you get a 502 Bad gateway error? Just follow these steps and it will probably be enough to make your application work…
Modifying SELinux Policy Rules
1 2 3 |
|
Once done, make sure to restart your server via Digital Ocean’s dashboard utility.
Systemd
To make our gunicorn_start script run as a system service so that, even if we are no longer logged into the server, it still serves our Django web application, we need to create a systemd service.
Just change the working directory to /etc/systemd/system, and then create a service file:
1 2 |
|
Add the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Save and exit, and then start the service and enable it:
1
|
|
NOTE: If you encounter an error, run
journalctl -xe
to see more details.
Finally, enable the service so that it runs forever and restarts on arbitrary shut downs:
1
|
|
Sanity Check (final!)
Check for the status of the service:
1
|
|
Now just visit your server’s IP address (or hostname) and you will see a Django error page. To fix this, run the following command in your project’s root directory (with your virtualenv activated):
1
|
|
Now you are good to go, and you will see the Django web app running on the web browser with all the static files (HTML/CSS/JS) files working.
For further reference grab the code from the repository. Add your questions/comments/concerns below. Cheers!