It is useful to make your development environment similar to the production environment to eliminate lot of the problems caused by the inconsistencies between the two. In this tutorial we create an environment that is pretty close to something you could use in production except we will be using the Django development server instead of something like Nginx + Gunicorn to serve the pages.

Install Vagrant And Virtualbox

Go to Vagrant Boxes Search and search for Ubuntu. You can see that there is a box called Official Ubuntu 16.04 LTS (Xenial Xerus) Daily Build, let’s use that. (VisitUbuntu Releases to see current status of Ubuntu releases).

In the Vagrant Boxes Search you can see that the provider for the box is VirtualBox.

Download and install latest Vagrant and VirtualBox releases:

Vagrant Download

VirtualBox Download

Create The Environment

Create a folder somewhere and install the box:

1
2
3
4
5
cd ~/Projects
mkdir mysite
cd mysite
vagrant init ubuntu/xenial64
vagrant up

If you haven’t used this box before it will download it. This might take some time.

SSH To The System

1
vagrant ssh

You might need to setup locales to suppress messages like this: “WARNING! Your environment specifies an invalid locale.”:

1
sudo vim /etc/environment
1
2
LC_ALL=en_US.UTF-8
LANGUAGE=en_US.UTF-8

Run updates:

1
sudo apt-get update && sudo apt-get dist-upgrade

Create A User For The Site

Create a new user for the site and add it to the sudo group to grant superuser privileges:

1
2
sudo adduser mysite
sudo adduser mysite sudo

Switch to the new user:

1
su - mysite

Hyphen (-) after su will switch the folder to the home directory of the new user and changes environmental variables to those of the new user.

Create A Virtual Environment

Create a virtual environment with venv, activate it and install django. It prompted to upgrade pip so I did that too:

1
2
3
4
5
sudo apt install python3-venv
python3 -m venv venv
source venv/bin/activate
pip install django
pip install --upgrade pip

Check this tutorial on how to use virtualenvwrapper to manage virtual environments.

Forward Port

Go to your host machine project folder, create a folder called mysite inside it (we will map it to the Django project root inside the virtual machine):

1
2
cd ~/Projects/mysite
mkdir mysite

You should now have this kind of folder structure:

1
2
3
4
mysite
├── Vagrantfile
├── mysite
└── ubuntu-xenial-16.04-cloudimg-console.log

Edit the Vagrantfile.

Uncomment this line:

1
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

And change the guest port to 8080:

1
config.vm.network "forwarded_port", guest: 8080, host: 8080, host_ip: "127.0.0.1"

This means that we can now access the Django development server in http://127.0.0.1:8080 from the host machine browser.

Because we defined the host_ip, this means that we can only access the guest machine from that specific ip (localhost). Otherwise we would potentially give an open access to the machine from the network.

Sync A Folder

Write the following uncommented line under the example line:

1
2
# config.vm.synced_folder "../data", "/vagrant_data"
config.vm.synced_folder "mysite", "/home/mysite/mysite", owner: "mysite", group: "mysite", mount_options:["dmode=775,fmode=664"]

This will sync the host folder mysite to the /home/mysite/mysite inside the box.

It is important to set the owner, group and mount_options properly for this to work.

Reload the box:

1
vagrant reload

The folder ~/Projects/mysite/mysite should be now synced to the folder /home/mysite/mysite.

Create Django Project

Login to the virtual machine, change to the user mysite, activate the virtual environment and create a new Django project:

1
2
3
4
5
vagrant ssh
su - mysite
source venv/bin/activate
cd mysite
django-admin.py startproject mysite .

Now you should have this kind of folder structure inside the mysite home folder:

1
2
3
4
5
6
7
mysite
├── manage.py
└── mysite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

The deepest mysite folder at this point is in /home/mysite/mysite/mysite.

Run Development Server

1
python3 manage.py runserver

Development server should now be available in http://127.0.0.1:8000/. You can test it locally with a command line browser like links.

Open a new terminal tab and connect to the server again:

1
2
3
4
5
6
vagrant ssh
su - mysite
source venv/bin/activate
cd mysite
sudo apt install links
links http://127.0.0.1:8000/

Now you should see the default text: Congratulations on your first Django-powered page….

Use q to exit links.

But since we setup the port forwarding, we can access the development server also from the host machine. Stop the development server with ctrl + c and run it with this command:

1
python3 manage.py runserver 0:8080

Access the server from the host with http://localhost:8080 or http://127.0.0.1:8080.

127.0.0.1 is not accessible outside the virtual machine. 0 makes the development server available from all IPs your computer responds to (0 is shortcut for 0.0.0.0). Read more about runserver

Create PostgreSQL User And Database

The default project uses SQLite as database. (You might have noticed the database file that was created in /home/mysite/mysite/db.sqlite3)

SQLite is a serverless database contained in a single file. For Django production sites you should use something like PostgreSQL

1
sudo apt install postgresql postgresql-contrib

postgresql-contrib contains some extra functionality.

The installation created a new user account called postgres. Let’s use that to create a new role (database user) and a database:

1
sudo -u postgres createuser mysite -P

-P prompts for password for the user to be created createuser - postgresql.org

Create the database and set owner as mysite:

1
sudo -u postgres createdb mysite -O mysite

-O sets the owner of the database. createdb - postgresql.org

Install Psycopg2 And Configure Settings file

1
pip install psycopg2

Psycopg is a PostgreSQl adapter for Python.

Edit the settings file:

1
vim mysite/settings.py

Comment out the default DATABASES settings and add new for PostgreSQL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#DATABASES = {
#    'default': {
#        'ENGINE': 'django.db.backends.sqlite3',
#        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#    }
#}

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'mysite',
        'USER': 'mysite',
        'PASSWORD': 'mysite',
        'HOST': 'localhost',
        'PORT': '',
    }
}

You can now delete the SQLite file and run Migrate:

1
2
rm db.sqlite3
python3 manage.py migrate

You can examine the database to see that the tables are actually created:

1
2
3
sudo -u postgres psql mysite
\d
\q

Psql connects to the database. \d shows tables. \q quits the terminal.

Note: Psql is an interactive terminal for PostgreSQL.

Create A Superuser

Create a superuser so we can access the admin area:

1
python3 manage.py createsuperuser

Visit http://127.0.0.1:8080/admin/.

Editing The Files

Because we shared the mysite folder, you can edit the files also from the host machine with your favourite editor like Emacs or PyCharm.

GIT

You might want to initialize a GIT repository at this point:

Create a .gitignore file…

1
2
cd /home/mysite/mysite
vim .gitignore

…with these lines:

1
2
3
__pycache__/
*.py[cod]
.idea/

You want to ignore at least the cache and editor config files (.idea folder is for PyCharm).

1
2
3
git init
git add .
git commit -m"Initial"