Productivity Sync Just another WordPress weblog

October 18, 2016

Setting up a Digital Ocean Django host using latest Ubuntu LTS and Django releases. (circa Oct 2016)

Filed under: Uncategorized — admin @ 10:48 am

This is a blog of my experience working through the on line tutorials from Digital Ocean (DO).  I’ve initially set up my DO site using some canned images for ubuntu 14.04 and older python versions that I don’t want to use.  So, after getting some experience with getting things working the easy way its now time to redo things using the versions I want to use.  This will document the gotchas and type-oh mistakes made in the process of getting things working.

The source content I’m following are:

Note: I first set up a server privately last week and had a number of gotchas and issues that I managed to work around with the assorted configuration files and settings but, didn’t keep good notes.  Mostly fat finger issues but, at least one issue was because of minor changes to the way Django handles configurations WRT the version used in the DO tutorial.  This is my cheat sheet for me later if I need to set up another sever someday.

Wow, the second time was a pain in the butt too!  more fat finger issues and hard to debug logging, see end of the blog for screw up vectors.

Setting up the “Droplet”

  1. log on to your DO account
  2. create droplet
    1. I chose: Ubuntu 16.04.1 x64, 5$/month plan, SFO data center region,
    2. gotcha: do not choose to use SSH when creating the droplet.  The SSH key will be used in the root log in and I’ve had issues getting that working and had to rebuild without it.  Note: DO doesn’t seen passwords if you choose ssh key from the droplet create screen.  Its better to log in and then set up the SSH stuff by hand I think.  (well, I couldn’t log on with SSH because I don’t do SSH as root and prefer to use a non-root ssh log in and the su into root as needed)
    3. Setup gotcha, creating the initial droplet has about a 5 min latency.  so don’t be shocked if the web based console doesn’t work right away.  Just try again after 5 to 10 min.
    4. Note: the root password will be emailed to your DO registered email account.
    5. gotcha : the DO console logged me on and then seemed to crash while I was changing the default password.  I worked around this by SSH’ing using the bash shell from windows 10.
    6. Initial PW changed and I’m now logged in and ready to follow the initial server setup with ubuntu 16.06 instructions.
  3. server setup:
    1. root log in (initial PW change)
    2. user account # adduser scary
    3. set up sudo’er # usermod -aG sudo scary
    4. install ssh key to user account: ssh-copy-id scary@138.xx.xx.xxx  <– IP partial redacted to avoid attacks before I set up fire wall.
      1. test ssh log in to user account. ssh scary@138.xx.xx.xxx
      2. test sudo su works.  from the ssh console do “sudo su” check that you are root.
    5.  sudo vim /etc/ssh/sshd_config :
      PasswordAuthentication no; PubkeyAuthentication yes; ChallengeResponseAuthentication no
    6. restart sshd : sudo systemctl reload sshd
    7. test log in from new local term: ssh scary@138.xx.xx.xxx
    8. basic firewall :
      1.  1 sudo ufw app list
         2 sudo ufw enable   <-- gotcha!  I forgot to ufw allow OpenSSH first!!!!  
         3 sudo ufw status
         4 ls
         5 sudo ufw allow OpenSSH
         6 sudo ufw status
    9. change root loggin pw to something nasty using uuidgen; sudo su; passwd; to set a passwd that is hard to attack.  you won’t need to be loggin in as root anyway so turn off root log ons or set a one time passwd that is nasty and loose it.
    10. Done.  Luckily I did’t mess up things too badly and was able to recover from the ufw screw up because I kept a few ssh log-ins running while I set up the ufw.
  4. Setting up the web server. Initial Server Setup with Ubuntu 16.04
    1. apt-get packages and upgrade server:
      1.  11 sudo apt-get update
         12 sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx
         13 sudo apt-get upgrade
    2. Create PostgreSQL database and user  (don’t forget the ; at the end of the postgres commands you enter):
      1. sudo -u postgres psql
        psql (9.5.4)
        Type "help" for help.
        
        postgres=# CREATE DATABASE scary-stuff;
        ERROR: syntax error at or near "-"
        LINE 1: CREATE DATABASE scary-stuff;
         ^
        postgres=# CREATE DATABASE scarystuff;
        CREATE DATABASE
        postgres=# CREATE USER scary WITH PASSWORD 'xxxxxx-xxx-xxx-xxxx-xxxxxxx';
        CREATE ROLE
        postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
        ERROR: role "myprojectuser" does not exist
        postgres=# ALTER ROLE scary SET client_encoding TO 'utf8';
        ALTER ROLE
        postgres=# ALTER ROLE scary SET default_transaction_isolation TO 'read committed';
        ALTER ROLE
        postgres=# ALTER ROLE scary SET timezone TO 'UTC';
        ALTER ROLE
        postgres=# GRANT ALL PRIVILEGES ON DATABASE scarystuff TO scary
        postgres-# \q
    3. Set up python virtual environment for my progect:
      1.  sudo pip3 install virtualenv
        scary@scary-1604-512mb-sfo2-01:~/myproject$ virtualenv venv
        scary@scary-1604-512mb-sfo2-01:~/myproject$ . venv/bin/activate
        (venv) scary@scary-1604-512mb-sfo2-01:~/myproject$ python
        Python 3.5.2 (default, Sep 10 2016, 08:21:44)
        [GCC 5.4.0 20160609] on linux
        Type "help", "copyright", "credits" or "license" for more information.
        >>>
        (venv) scary@scary-1604-512mb-sfo2-01:~/myproject$ deactivate
    4. install Django, gunicorn, psycopg2:
      1. scary@scary-1604-512mb-sfo2-01:~/myproject$ . venv/bin/activate
        
        (venv) scary@scary-1604-512mb-sfo2-01:~/myproject$ pip install django gunicorn psycopg2
        ...
        Successfully installed django-1.10.2 gunicorn-19.6.0 psycopg2-2.6.2
    5. set up an configure default Djanog project “django-admin startproject myproject; vim myproject/myproject/settings.py” :
      1. DATABASES = {
        
         'default': {
        
         'ENGINE': 'django.db.backends.postgresql_psycopg2',
        
         'NAME': 'scarystuff',
        
         'USER': 'scary',
        
         'PASSWORD': '12345678-1234-1234-1234-1234567890ab',   <-- bogus pword
        
         'HOST': 'localhost',
        
         'PORT': '',
        
         }
        
        }
      2. STATIC_URL = '/static/'
        
        STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
    6. Complete django initial project setup:  (if you screw this up you’ll loose a day to debugging gunicorn and nginx cofigs)
      1.  django-admin startproject myproject     <-- this is where I fucked up! missing period at the end
         35 vim myproject/myproject/settings.py
         36 history
         37 ls
         38 cd myproject/
         39 ls
         40 ./manage.py makemigrations
         41 ./manage.py migrate
         42 ./manage.py createsuperuser
         43 ./manage.py collectstatic
         44 sudo ufw allow 8000
         45 ./manage.py runserver 0.0.0.0:8000
      2. test by hitting the test server from a browser.  Be sure to test both main page and /admin page.  You need to look for any css issues and fix them if you have em…  (when I set up on my local test image I messed up settings.py around the static files and had to fix things up. this time things are going better… fewer fat finger events)
    7. Testing gunicorn note admin site should be missing its css data when served when run this way:
      1.  gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application
        [2016-10-17 15:04:52 +0000] [30271] [INFO] Starting gunicorn 19.6.0
        [2016-10-17 15:04:52 +0000] [30271] [INFO] Listening at: http://0.0.0.0:8000 (30271)
        [2016-10-17 15:04:52 +0000] [30271] [INFO] Using worker: sync
        [2016-10-17 15:04:52 +0000] [30274] [INFO] Booting worker with pid: 30274
        Not Found: /static/admin/css/base.css
        Not Found: /static/admin/css/dashboard.css
        ^C[2016-10-17 15:05:23 +0000] [30271] [INFO] Handling signal: int
        [2016-10-17 15:05:23 +0000] [30274] [INFO] Worker exiting (pid: 30274)
        [2016-10-17 15:05:23 +0000] [30271] [INFO] Shutting down: Master
        (venv) scary@scary-1604-512mb-sfo2-01:~/myproject/myproject$ deactivate
    8. create gunicorn systemd service file:
      1. sudo vim /etc/systemd/system/gunicorn.service
        [sudo] password for scary:
        $ cat /etc/systemd/system/gunicorn.service
        
        [Unit]
        Description=gunicorn daemon
        After=network.target
        
        [Service]
        User=scary
        Group=www-data
        WorkingDirectory=/home/scary/myproject
        ExecStart=/home/scary/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/scary/myproject/myproject.sock myproject.wsgi:application
        
        [Install]
        WantedBy=multi-user.target
      2.  sudo systemctl start gunicorn
        sudo systemctl enable gunicorn

        1. I get errors here: “Failed to execute operation: Invalid argument.
        2. I found a cut and paste issue in the gunicorn.service file. duh first line was buggered…<<fixed>>
        3. silent failure after fixing this problem  with gunicorn not finding wsgi.py  (because of screw up on django-admin command line used that dropped the period at the end of the line.)
        4. run systemctl to see the daemons and noted that gunicorn was having problems.
          1. grep gunicorn /var/log/syslog to see some clues.
    9. configure Nginx to proxy pass to gunicorn
      1.  83 sudo vim /etc/nginx/sites-available/myproject
         84 sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/
         85 sudo nginx -t
         86 sudo systemctl restart nginx
         87 sudo ufw delete allow 8000
         88 sudo ufw allow 'Nginx Full'
        
        scary@scary-1604-512mb-sfo2-01:~$ cat /etc/nginx/sites-available/myproject
        server {
         listen 80;
         server_name 138.68.13.110;
        
         location = /vavicon.ico { access_log off; log_not_found off; }
         location = /static/ {          <-- the equals sign is wrong!!!!!
         root /home/scary/myproject;
         }
        
         location / {
         include proxy_params;
         proxy_pass http://unix:/home/scary/myproject/myproject.sock;
         }
        
        }
      2. errors after getting this far:
        1. 502 Bad Gateway
    10. Debug:  I have 2 issues.  gunicorn is complaining on systemctl activate, and ngix is serving a 502 🙁
      1. tripple check I followed instructions well.
        1. found a cut and paste issue in the gunicorn.service file. <<fixed>>
      2. look at the error logs:
        1. [crit] 2597#2597: *1 connect() to unix:/home/scary/myproject/myproject.sock failed (2: No such file or directory) while connecting to upstream, client: 50.53.49.126, server: 138.68.13.110, request: “GET / HTTP/1.1”, upstream: “http://unix:/home/scary/myproject/myproject.sock:/”, host: “138.68.13.110”
        2. myproject.sock is a file created by gunicorn.  but gunicorn isn’t putting out errors.
        3. Runs systemctl see a list of services.  note that gunicorn is still bad.
          1. ● gunicorn.service loaded failed failed gunicorn daemon
          2. grep /log for gunicorn shows:
            1. /var/log/syslog:Oct 18 16:13:16 scary-1604-512mb-sfo2-01 gunicorn[1731]: ImportError: No module named ‘myproject.wsgi’
              1. root cause of this was the django-admin line I used where I left off the period at the end.
        4. type-oh’s in nginx config :
          1. location = /static/ is wrong.  The equals sign is bogus.
    11. done now it works !

Holy shit there are all sorts of ways to fat finger the setup of a server!

  1. forgot the period at the end of the django-admin.py command line that results in an extray myproject subdirectory that confuses things.
  2. I inserted an = in the nginx config file messing up static file serving
  3. had a bogus cut and paste line in my initial gunicorn.service file.

 

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress