Deploying my first Django app

Hello everyone,

As a CS student, I created my portfolio website using Django which I would like to deploy.

I have some questions and will be much appreciated if anyone can help.

  1. Can you guys suggest some cheap hosting for my website? I won’t have much traffic so the cheapest option possible that will run the app optimally.

  2. I have some files (photos, logos, and js and css scripts) that are in folders mentioned inside settings.py.
    So I have the following code for static files and media:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = (
    '/home/user/Documents/Projects/Django/portfolio/static',
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    )

#Media_Root is for server path to store files in the computer
MEDIA_ROOT =  os.path.join(BASE_DIR, 'media')
#Media_URL is the reference URL for the browser to access the files over Http
MEDIA_URL = '/media/'

My question is when the project is on the server, so do I just change the static path from:

/home/user/Documents/Projects/Django/portfolio/static

to:

some/folder/on/server/static
  1. I installed an app called “mathfilters” with pip3 install mathfilters.
    Once the project is on the server do I need to install the app again or it is already installed inside the project directories.
  2. I created a model for my projects:
class Project(models.Model):
    project_name = models.CharField(max_length=120)
    project_description = models.CharField(max_length=400)
    project_link = models.CharField(max_length=500)
    project_image = models.ImageField(upload_to='images/')

So instead of editing every time the HTML template I can just add a project through the admin page and it will show on the website.
Now, can I just change the admin path instead of http://127.0.0.1:8000/admin/ to something like http://127.0.0.1:8000/sdfkjsdkfja(A)Sd9asdjk!-304-032@asdlkdf9uigr/ so I can be the only one having access to the admin panel. If I do that is there a way for someone to find this path and eventually brute force the form and log into admin as a superuser?

  1. Is the local Django database that I have used in developing mode will be migrated to the server with the data already in and if yes can I keep using it?

Regards

As always, I recommend starting with the official Django docs, in this case, the page on Deploying Django. And among all the references on that page, I’ll make a specific reference to the Deployment Checklist that should also be high on your to-read list.

To answer some of your questions:

  1. Covered by the docs, but briefly, yes.

  2. You will probably need to set up your environment again - not just mathfilters, but also Django and all the other packages you may be referencing in your application. (The most notable exception is the technique first mentioned to me by @adamchainz, and that’s if you include your virtual environment within your project directory - in which case, all those packages would be brought along.)

  3. Changing your admin URL is strongly recommended. But it doesn’t need to be anything exceptionally fancy or difficult. My personal experience has been that more than 99% (and yes, that’s a real number) of all the “attacks” on my web site have come from “scripts” having been run looking for the same set of URLs with known vulnerabilities. Unless you’ve got a really high-profile site, or have made some serious enemies, people aren’t going to manually look for exploits. They’re running scripts against every web site they can find, just trying to see what they can get access to. Just changing /admin to /some-admin (not the real URL) has reduced the rate of attacks by an order of magnitude. (I still see the standard assortment of WordPress and Drupal attacks, but those don’t concern me any more.)

  4. Short answer is no. Depending upon how you’re doing your local development, and the hosting provider, you probably can’t migrate the database itself. I provide assistance on one site where the hosting provider provides access to a MySQL instance - I have to use their database server with the database name and username that I’m assigned. So I had to unload the data locally and run a script to load it remotely.

<Opinion>Deploying a Django site to a live environment the first time is one of the most intricate (and likely painful) activities you’ll ever deal with when working with Django.</Opinion>

Ken

Hi Ken,

Thanks for your reply again.

I have been up all night and currently setting up my server. I picked linode as they provide
cheap hosting.
I installed my venv, all django packages and I am currently installing apache2.
Question 1-5 are already covered so I am half way through.
Interesting thing is that I run the server on port 8000 just for testing purposes and accessed the website from external browser and all the data from the development was there (I used django’s DB). Hopefully it will stay until properly deployed.

Regards

If you’re talking about SQLite, yes, that exists as a single file that can be copied with your data. And, if your expected usage of this site is light, then it may work perfectly well for you. Just be aware that there is some level of activity, beyond which, you will start to encounter errors.

This is not to say that using it is wrong - there are many cases where SQLite is the right choice. So just consider this as an “awareness” issue. (I’ve got roughly a half-dozen production sites using it as their database. But I know what the limits and gotcha’s are, and know that I’m ok with it.)

Ken

On accessing my website through IP address gives me Error 500.
I tried to look at the logs but couldn’t find where the issue is. Maybe you guys can spot something I am not able to.

This is the apache2 error log:

[Fri Jun 19 05:39:16.859990 2020] [mpm_event:notice] [pid 3911:tid 139907929836480] AH00491: caught SIGTERM, shutting down
[Fri Jun 19 05:39:16.965359 2020] [mpm_event:notice] [pid 4312:tid 140643133819840] AH00489: Apache/2.4.29 (Ubuntu) mod_wsgi/4.5.17 Python/3.6 configured -- resuming normal operations
[Fri Jun 19 05:39:16.965493 2020] [core:notice] [pid 4312:tid 140643133819840] AH00094: Command line: '/usr/sbin/apache2'
Exception ignored in: <bound method BaseEventLoop.__del__ of <_UnixSelectorEventLoop running=False closed=False debug=False>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/asyncio/base_events.py", line 526, in __del__
NameError: name 'ResourceWarning' is not defined
[Fri Jun 19 05:59:05.767919 2020] [mpm_event:notice] [pid 4312:tid 140643133819840] AH00491: caught SIGTERM, shutting down
[Fri Jun 19 05:59:05.878664 2020] [mpm_event:notice] [pid 4506:tid 140707700038592] AH00489: Apache/2.4.29 (Ubuntu) mod_wsgi/4.5.17 Python/3.6 configured -- resuming normal operations
[Fri Jun 19 05:59:05.878816 2020] [core:notice] [pid 4506:tid 140707700038592] AH00094: Command line: '/usr/sbin/apache2'

Access log:

80.6.211.165 - - [19/Jun/2020:06:05:30 +0000] "GET / HTTP/1.1" 500 387 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0"
80.6.211.165 - - [19/Jun/2020:06:05:37 +0000] "GET / HTTP/1.1" 500 387 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0"
80.6.211.165 - - [19/Jun/2020:06:05:37 +0000] "GET /favicon.ico HTTP/1.1" 404 432 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0"

EDIT: I switched back to debugging and it turns out it cannot find my templates. The problem was fixed

Accessing the website gives me Error 403 , it denies the access to it. Now I know what you meant when you said that setting django app for the first time is a pain.
Here is my apache2 error.log:

[Sat Jun 20 00:09:08.059177 2020] [authz_core:error] [pid 27955:tid 140025622669056] [client 80.6.211.165:59418] AH01630: client denied by server configuration: /home/anton/portfolio/venv/portfolio/wsgi.py
[Sat Jun 20 00:09:09.431907 2020] [authz_core:error] [pid 27955:tid 140025614276352] [client 80.6.211.165:59418] AH01630: client denied by server configuration: /home/anton/portfolio/venv/portfolio/wsgi.py
[Sat Jun 20 00:09:10.874735 2020] [authz_core:error] [pid 27955:tid 140025605883648] [client 80.6.211.165:59418] AH01630: client denied by server configuration: /home/anton/portfolio/venv/portfolio/wsgi.py
[Sat Jun 20 00:09:12.678584 2020] [authz_core:error] [pid 27955:tid 140025597490944] [client 80.6.211.165:59418] AH01630: client denied by server configuration: /home/anton/portfolio/venv/portfolio/wsgi.py

I copied the apache sites-available config file and made my own custom one django-project.conf were I added those settings:

Alias /static /home/anton/portfolio/static
        <Directory /home/anton/portfolio/static>
                Require all granted
        </Directory>

        Alias /media /home/anton/portfolio/media
        <Directory /home/anton/portfolio/media>
                Require all granted
        </Directory>

        <Directory /home/anton/portfolio/venv/portfolio>
                <Files wsgi.py>
                        Require all granted
                </Files>
        </Directory>

        WSGIScriptAlias / /home/anton/portfolio/venv/portfolio/wsgi.py
        WSGIDaemonProcess django_app python-path=/home/anton/portfolio python-home=/home/anton/portf$
        WSGIProcessGroup django_app

My Project has the following structure:

image

Any help would be appreciated :frowning:

EDIT: there is new trace back:

[Sat Jun 20 00:24:43.930132 2020] [core:notice] [pid 28238:tid 140135741098944] AH00094: Command line: '/usr/sbin/apache2'
[Sat Jun 20 00:24:46.568074 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620] mod_wsgi (pid=28241): Target WSGI script '/home/anton/portfolio/venv/portfolio/wsgi.py' cannot be $
[Sat Jun 20 00:24:46.568142 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620] mod_wsgi (pid=28241): Exception occurred processing WSGI script '/home/anton/portfolio/venv/portfo$
[Sat Jun 20 00:24:46.568802 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620] Traceback (most recent call last):
[Sat Jun 20 00:24:46.568888 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/home/anton/portfolio/venv/portfolio/wsgi.py", line 16, in <module>
[Sat Jun 20 00:24:46.568894 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     application = get_wsgi_application()
[Sat Jun 20 00:24:46.568902 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/home/anton/portfolio/venv/lib/python3.6/site-packages/django/core/wsgi.py", line 12, in g$
[Sat Jun 20 00:24:46.568905 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     django.setup(set_prefix=False)
[Sat Jun 20 00:24:46.568912 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/home/anton/portfolio/venv/lib/python3.6/site-packages/django/__init__.py", line 19, in se$
[Sat Jun 20 00:24:46.568916 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
[Sat Jun 20 00:24:46.568923 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/home/anton/portfolio/venv/lib/python3.6/site-packages/django/conf/__init__.py", line 76, $
[Sat Jun 20 00:24:46.568926 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     self._setup(name)
[Sat Jun 20 00:24:46.568933 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/home/anton/portfolio/venv/lib/python3.6/site-packages/django/conf/__init__.py", line 63, $
[Sat Jun 20 00:24:46.568936 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     self._wrapped = Settings(settings_module)
[Sat Jun 20 00:24:46.568942 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/home/anton/portfolio/venv/lib/python3.6/site-packages/django/conf/__init__.py", line 142,$
[Sat Jun 20 00:24:46.568954 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     mod = importlib.import_module(self.SETTINGS_MODULE)
[Sat Jun 20 00:24:46.568961 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
[Sat Jun 20 00:24:46.568964 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]     return _bootstrap._gcd_import(name[level:], package, level)
[Sat Jun 20 00:24:46.568970 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 994, in _gcd_import
[Sat Jun 20 00:24:46.568976 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 971, in _find_and_load
[Sat Jun 20 00:24:46.568982 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 941, in _find_and_load_unlocked
[Sat Jun 20 00:24:46.568988 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
[Sat Jun 20 00:24:46.568994 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 994, in _gcd_import
[Sat Jun 20 00:24:46.569001 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 971, in _find_and_load
[Sat Jun 20 00:24:46.569007 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620]   File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
[Sat Jun 20 00:24:46.569024 2020] [wsgi:error] [pid 28241:tid 140135627290368] [remote 80.6.211.165:59620] ModuleNotFoundError: No module named 'portfolio'

I’m hoping someone else can jump in here - I haven’t used this configuration in about 10 years.

Unfortunately, it looks like the WSGIDaemonProcess configuration line is cropped. What are the values of python-home and python-path? But importantly, notice the difference between the two in the documentation. python-home is a reference to the base dir of your python environment, not your project (unless your virtual environment is contained within your project). Also, from what I can tell, python-path should point to /home/anton/portfolio/venv.

<Opinion>Generally speaking, you don’t want your code to live in the /home/ set of directories. Apache is running under a different user id than yours. You want to move your project to some “neutral” location, perhaps something under /var/ or /opt/, and then make sure that entire directory structure can be accessed by the id being used to run that process.</Opinion>

Ken

Well, I had to give up on apache and use nginx and gunicorn. The setup is much easier and straightforward, but I am not sure if it is the best technology to use.
I followed this tutorial (not sure if I am allowed to post videos here): https://www.youtube.com/watch?v=hYMTvK5MpQI and had a deployed website in 30 min.

Regards

I agree - personally, I use nginx and uwsgi, which is effectively about the same thing.

Glad to see you have it working!

1 Like