Gunicorn post

master
Tait Hoyem 4 years ago
parent 2d6c61088d
commit a6a75b643b

@ -0,0 +1,81 @@
---
title: "The \"Quiz Your Friends\" XSS Exploit"
layout: post
---
## TODO write intro
## How I Found This Exploit
While filling in one of my friend's surveys I thought it would be
funny for them to know it is me without anyone else knowing.
We were young and had `Inspect Element`ed a few things together,
so it was a safe bet that an HTML joke would let them know.
So I typed in my name like so:
`BOLD_STEVE.JPG`
Now in theory this should have shown in in the leaderboard as: "<b>Bold Steve</b>"
However, to my horror and excitement, I saw this in the leaderboard:
`BOLD_STEVE_LEADERBOARD.JPG`
The text "Bold Steve" showed up **in bold** on the leaderboard.
This told me all I needed to know. To add a `<script>` tag was next.
#### Hacking:
So I went on my merry way thinking about ways to use malicious javascript.
Then, I thought that might be mean, so I decided to warn users instead.
I filled in the name with a script tag and a call to `alert()` to warn the user about this site.
`JAVASCRIPT_NAME.JPG`
I ran out of room before I could finish it. Hmmm.
What if I do "Inspect Element" and manually override the max-length attribute?
The unfortunate truth is: this worked as well!
Not only could I manually set the max-length by changing it in the HTML,
but there were no client-side OR server-side checks to make sure the name I was sending was less than or equal to 20 characters.
If Javascript checked it, it would have stopped me (although maybe not a professional).
If the server checked it, it could have stopped almost anyone.
##### Server-Side Validation
As a side note, here is a great reason why you should do most of your validation on the server side.
As a user, I can edit any of the HTML, CSS, or Javascript your server serves to me.
Imagine trying to fit in a script tag doing anything useful with 20 characters?
`<script src="http:">`
There's your 20 characters! No more! Good luck trying to do anything useful with this!
The Quiz My Friends server has *no such checks in place*.
Therefore, I can send an almost arbitrary load to them.
Being able to send something potentially very large (more than a few megabytes) is a vulnerability of its own.
Imagine being able to send entire executable progrmas as your "name" in one of these quizes?
## Executing An Exploit
Suppose we're on a vulnerable site like [Quiz Your Friends](https://www.quizyourfriends.com/)
and you decide you want to hack your friend's quiz!
How can this be done?
#### Creating A Quiz
Here is my quiz below:
`CREATING_QUIZ.IMG`
#### Setting A Name With an HTML Tag
Just like the image above, about how I found out about this vulnerability: go ahead and use an HTML tag in your name to test this out.
`BOLD_ITALIC_STEVE.JPG`

@ -0,0 +1,6 @@
- institution: "Dartmouth College (Open Corseware)"
level: "Professional Certificate"
name: "C Programming with Linux"
years: "2020"
description: "A certification in C programming, the `gcc` compiler, and the `make` compilation system."
link: "https://credentials.edx.org/credentials/17b2f07e656d4d61a27153716c97a404/"

@ -1,9 +1,6 @@
- name: "epub-with-pinyin"
link: "https://github.com/TTWNO/epub-with-pinyin"
description: "A program which adds Mandarin Pinyin notation above Chinese characters in .epub files."
- name: "ttrpg.co"
link: "https://ttrpg.projects.tait.tech/"
description: "An work-in-progress accessible table-top-role-playing-game."
- name: "Chess"
link: "https://github.com/TTWNO/chess"
description: "A chess app written in C++"

@ -0,0 +1,17 @@
{% for types in site.data.links %}
<h2>{{ types.heading }}</h2>
<section class="contact-info">
{% for info in types.values %}
<p><span>{{ info.name }}</span> -
<a href="{{ info.value }}" class="mono">
{% if info.label != "INHERIT" %}
{{ info.label }}
{% else %}
{{ info.value }}
{% endif %}
</a></p>
{% endfor %}
</section>
{% endfor %}
All my big projects are on my [homepage](/).

@ -0,0 +1,122 @@
---
title: "How to Solve The Django Deployment Puzzle"
layout: post
---
A few days ago I had a Django project I wanted to put on a real server.
This project is still in its infancy, but I thought it would be nice to put it on my resume and show my friends.
Little did I know the headache coming my way.
Here are some tips to help you not make the same mistakes as me.
### ASGI Servers
Because my project used the ASGI (Asynchronous webServer Gateway Interface),
I needed to find a good production ASGI server to handle all the incoming requests.
The best thing I found was [uvicorn](http://www.uvicorn.org/).
It focuses on speed, which is a priority, especially when using the ASGI protocol.
To run uvicorn on the command line for testing purposes, use something like the following:
<pre class="terminal">
$ uvicorn --reload myapp.asgi:application
</pre>
The `--reload` option says to reload the server if any of the files get updated.
This is not recommended in production.
Sadly, I thought this meant I would need to do a hard shutdown of the server process every time I wanted to update.
This turned out to not be the case.
### Workload Managers
There is another equine-named program called [gunicorn](https://gunicorn.org/)
which can hold a number of processes under its control.
An interesting feature of `gunicorn` is that it will gracefully switch from an old to a new deployment,
replacing the subprocesses one-by-one and eventually having only the new deployment active on all subprocesses.
The greatest part? Zero down time.
The server keeps any old processes open if there is communication with them,
then shift and new connections to the new deployment.
This was a very cool feature I wanted to take advantage of.
"Now hold on!" you might protest.
"gunicorn is a WSGI server!" ... oh you got me there!
Yes, that's right, `gunicorn` is paired with `uvicorn` to serve my files.
### systemd
Love it or hate it, the majority of Linux distributions use the `systemd` init system.
I decided it would be very convenient to have a .service file for my Django application to run automatically at boot.
`Systemd` allows me to do this with a file like the following one I stored in `/lib/systemd/system/lamegames.service`.
<pre class="file">
[Unit]
Description=Gunicorn/Uvicorn (lamegames.io)
[Service]
WorkingDirectory=/home/lame/lamegames.io
Type=simple
RemainAfterExit=yes
ExecStart=/home/lame/lamegames.io/env/bin/gunicorn lamegames.asgi:application -w 2 -k uvicorn.workers.UvicornWorker
ExecStop=/bin/kill -HUP $MAINPID
Restart=always
[Install]
WantedBy=multi-user.target
</pre>
### nginx
NGINX (pronounced engine-X) is a performance web server designed for speed and simplicity.
For the front facing side of the site, I do need a production web server like nginx.
Gunicorn simply doesn't need all the features that nginx provides, but I do.
To configure my nginx installation, I used the following few directives to:
1. Redirect most traffic towards the gunicorn server.
2. Redirect statically served files (CSS, JS, images) to the directory specified in the STATIC_ROOT variable of my `settings.py` file.
3. Use TLS to enable https://
Serving the static files from nginx as opposed to the `gunicorn` server is necessary.
Gunicorn and other production A/WSGI web server will not set the proper MIME type over TLS.
This will cause your browser to not load the Javascript/CSS.
This is the important part of my nginx config.
<pre class="file">
server {
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# these two lines ensure that WebSocket, and HTTP2 connection are forwarded correctly
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_redirect off;
proxy_buffering off;
# this forwards all traffic to the local server on port 8000
proxy_pass http://localhost:8000;
}
# This forwards all static requests to Django's STATIC_ROOT set in settings.py; it is generated using the collectstatic command.
location /static {
autoindex on;
alias /home/lame/lamegames.io/static_generated;
}
}
</pre>
### Setup
After all that, I was able to do the following:
<pre class="terminal">
# systemctl enable lamegames
</pre>
This enabled my `gunicorn` server to run once the server started.
NGINX is that way be default.
And tada! You now have a working Django project on a production server!
#### Notes
* If using ws:// websockets, change them to wss:// for secure web sockets.
* Make sure to use channels.routing.get_default_application() instead of django.get_asgi_application() if your're wanting to use channels/redis WebSockets.

@ -229,6 +229,15 @@ footer {
background-color: #151515;
}
.file {
overflow: scroll;
padding: 10px;
margin: 0px;
line-height: 1.2em;
background-color: #dfdfdf;
color: #000;
}
.small-image {
width: 100%;
}

@ -0,0 +1,163 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>How to Solve The Django Deployment Puzzle | tait.tech</title>
<link rel="stylesheet" href="/assets/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="wrapper">
<nav>
<input type="checkbox" id="menu">
<label for="menu">&#9776;</label>
<div class="menu-content">
<a href="/" class="nav-link" >Home</a>
<a href="/tutoring/" class="nav-link" >Tutoring</a>
<a href="/blog/" class="nav-link" >Blog</a>
<a href="/links/" class="nav-link" >Links</a>
<a href="https://github.com/TTWNO/" class="nav-link" target="_blank" rel="noopener noreferrer" >Code</a>
</div>
</nav>
<h1>How to Solve The Django Deployment Puzzle</h1>
<h4 class="post-date line-under">Sunday, August 16 2020</h4>
<div class="article">
<p>A few days ago I had a Django project I wanted to put on a real server.
This project is still in its infancy, but I thought it would be nice to put it on my resume and show my friends.
Little did I know the headache coming my way.
Here are some tips to help you not make the same mistakes as me.</p>
<h3 id="asgi-servers">ASGI Servers</h3>
<p>Because my project used the ASGI (Asynchronous webServer Gateway Interface),
I needed to find a good production ASGI server to handle all the incoming requests.
The best thing I found was <a href="http://www.uvicorn.org/">uvicorn</a>.
It focuses on speed, which is a priority, especially when using the ASGI protocol.</p>
<p>To run uvicorn on the command line for testing purposes, use something like the following:</p>
<pre class="terminal">
$ uvicorn --reload myapp.asgi:application
</pre>
<p>The <code class="highlighter-rouge">--reload</code> option says to reload the server if any of the files get updated.
This is not recommended in production.
Sadly, I thought this meant I would need to do a hard shutdown of the server process every time I wanted to update.
This turned out to not be the case.</p>
<h3 id="workload-managers">Workload Managers</h3>
<p>There is another equine-named program called <a href="https://gunicorn.org/">gunicorn</a>
which can hold a number of processes under its control.
An interesting feature of <code class="highlighter-rouge">gunicorn</code> is that it will gracefully switch from an old to a new deployment,
replacing the subprocesses one-by-one and eventually having only the new deployment active on all subprocesses.
The greatest part? Zero down time.
The server keeps any old processes open if there is communication with them,
then shift and new connections to the new deployment.
This was a very cool feature I wanted to take advantage of.</p>
<p>“Now hold on!” you might protest.
“gunicorn is a WSGI server!” … oh you got me there!
Yes, thats right, <code class="highlighter-rouge">gunicorn</code> is paired with <code class="highlighter-rouge">uvicorn</code> to serve my files.</p>
<h3 id="systemd">systemd</h3>
<p>Love it or hate it, the majority of Linux distributions use the <code class="highlighter-rouge">systemd</code> init system.
I decided it would be very convenient to have a .service file for my Django application to run automatically at boot.
<code class="highlighter-rouge">Systemd</code> allows me to do this with a file like the following one I stored in <code class="highlighter-rouge">/lib/systemd/system/lamegames.service</code>.</p>
<pre class="file">
[Unit]
Description=Gunicorn/Uvicorn (lamegames.io)
[Service]
WorkingDirectory=/home/lame/lamegames.io
Type=simple
RemainAfterExit=yes
ExecStart=/home/lame/lamegames.io/env/bin/gunicorn lamegames.asgi:application -w 2 -k uvicorn.workers.UvicornWorker
ExecStop=/bin/kill -HUP $MAINPID
Restart=always
[Install]
WantedBy=multi-user.target
</pre>
<h3 id="nginx">nginx</h3>
<p>NGINX (pronounced engine-X) is a performance web server designed for speed and simplicity.
For the front facing side of the site, I do need a production web server like nginx.
Gunicorn simply doesnt need all the features that nginx provides, but I do.
To configure my nginx installation, I used the following few directives to:</p>
<ol>
<li>Redirect most traffic towards the gunicorn server.</li>
<li>Redirect statically served files (CSS, JS, images) to the directory specified in the STATIC_ROOT variable of my <code class="highlighter-rouge">settings.py</code> file.</li>
<li>Use TLS to enable https://</li>
</ol>
<p>Serving the static files from nginx as opposed to the <code class="highlighter-rouge">gunicorn</code> server is necessary.
Gunicorn and other production A/WSGI web server will not set the proper MIME type over TLS.
This will cause your browser to not load the Javascript/CSS.</p>
<p>This is the important part of my nginx config.</p>
<pre class="file">
server {
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# these two lines ensure that WebSocket, and HTTP2 connection are forwarded correctly
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_redirect off;
proxy_buffering off;
# this forwards all traffic to the local server on port 8000
proxy_pass http://localhost:8000;
}
# This forwards all static requests to Django's STATIC_ROOT set in settings.py; it is generated using the collectstatic command.
location /static {
autoindex on;
alias /home/lame/lamegames.io/static_generated;
}
}
</pre>
<h3 id="setup">Setup</h3>
<p>After all that, I was able to do the following:</p>
<pre class="terminal">
# systemctl enable lamegames
</pre>
<p>This enabled my <code class="highlighter-rouge">gunicorn</code> server to run once the server started.
NGINX is that way be default.</p>
<p>And tada! You now have a working Django project on a production server!</p>
<h4 id="notes">Notes</h4>
<ul>
<li>If using ws:// websockets, change them to wss:// for secure web sockets.</li>
<li>Make sure to use channels.routing.get_default_application() instead of django.get_asgi_application() if yourre wanting to use channels/redis WebSockets.</li>
</ul>
</div>
<footer>
This page is mirrored on <a href="https://beta.tait.tech/2020/08/16/django-deployment.html">beta.tait.tech</a>.
</footer>
</div>
</body>
</html>

@ -90,6 +90,8 @@ footer { border-top: 1px solid #aaa; padding-top: 16px; margin-bottom: 100px; }
.terminal { line-height: 1em; overflow: scroll; padding: 10px; color: #00FF41; margin: 0px; background-color: #151515; }
.file { overflow: scroll; padding: 10px; margin: 0px; line-height: 1.2em; background-color: #dfdfdf; color: #000; }
.small-image { width: 100%; }
.post-date { font-size: 17px; text-transform: uppercase; font-weight: bold; color: rgba(0, 0, 0, 0.5); }

@ -7,8 +7,8 @@
],
"sourcesContent": [
"@import \"main\";\n",
"$normal-text-color: #444444;\n$nav-link-color: #333;\n$nav-link-hover-color: black;\n$link-color: #47a;\n$visited-link-color: #941452;\n\n$last-p-padd: 1.5em;\n$nav-padd: 1em;\n$line-under: 1px solid #aaa; \n\nbody {\n background-color: #fefefe;\n padding: 15px;\n font-family: -apple-system, helvetica, arial, sans-serif;\n}\n#wrapper {\n max-width: 800px;\n margin: auto;\n color: $normal-text-color;\n font-size: 14px;\n}\n#main-name {\n color: rgba(0, 0, 0, 0.8);\n}\n\nli {\n line-height: 1.5em;\n}\n\nh1 {\n font-size: 2.5em;\n}\nh2 {\n font-size: 2.0em;\n}\nh3 {\n font-size: 1.6em;\n}\nh4 {\n font-size: 1.3em;\n}\nh5 {\n font-size: 1.1em;\n}\na {\n text-decoration: underline;\n color: $link-color;\n} \na:visited {\n color: $visited-link-color;\n}\na.nav-link,\na.post-title-link {\n color: $nav-link-color;\n text-decoration: none;\n}\na.citation-link {\n text-decoration: none;\n}\n\n#img-wrapper img {\n margin-bottom: 10px;\n}\n\n#img-wrapper label {\n margin-left: 10px;\n}\n\nlabel {\n font-size: 12px;\n}\n\n#menu,\nlabel[for=\"menu\"]{\n display: none;\n}\n\nnav {\n padding: $nav-padd 0px;\n margin: 0px;\n}\nnav a:first-of-type {\n margin-left: 0;\n}\nnav a {\n margin: 1em;\n color: $nav-link-color;\n font-weight: bold;\n font-style: none;\n}\n/* TODO: Does not work */\n.on-page {\n color: #000;\n}\nnav a:hover {\n text-decoration: underline; \n}\n\nli {\n margin: .5em;\n}\n\n#main-img {\n width: 100%;\n}\np {\n font-size: 15px;\n line-height: 1.5;\n padding: .1em 0;\n}\n.line-under {\n padding-bottom: $last-p-padd;\n border-bottom: $line-under;\n}\n.article a:hover {\n color: rgba(0, 0, 0, 0.5);\n}\n\ntable,\ntable tr,\ntable td,\ntable th{\n border: 1px solid rgba(0, 0, 0, 0.5);\n border-collapse: collapse;\n padding: 5px;\n font-weight: normal;\n}\ntable th {\n font-weight: bold;\n}\ntable {\n width: 75%;\n margin: auto;\n}\n\ntable.post-list,\ntable.post-list tr,\ntable.post-list td {\n width: 100%;\n border: none;\n padding-left: 0;\n}\nimg {\n display: block;\n width: 55%;\n margin-left: auto;\n margin-right: auto;\n}\n\nblockquote {\n font-style: italic;\n}\n\n@media screen and (max-width: 600px){\n #menu,\n label[for=\"menu\"]{\n display: inline-block;\n font-size: 20px;\n }\n body {\n width: 90%;\n }\n #info {\n margin: 0 7px;\n }\n .menu-content {\n max-height: 0;\n overflow: hidden;\n }\n nav {\n width: 100%;\n }\n nav a {\n display: block;\n padding-left: 0;\n margin-left: 0;\n }\n input#menu{\n display: none;\n }\n input:checked ~ .menu-content {\n max-height: 100%;\n border-bottom: $line-under;\n color: red;\n }\n}\n\n.contact-info {\n width: 90%;\n margin: auto;\n word-wrap: break-word;\n}\n.contact-info p {\n margin: 7px;\n padding: 0;\n}\n\n.mono {\n font-family: monospace;\n}\n\n.bold {\n font-weight: bold;\n}\n\nsup {\n margin: 0;\n padding: 0;\n}\n\nfigcaption {\n margin-top: 10px;\n font-size: .8em;\n text-decoration: italic;\n}\n\nfooter {\n border-top: $line-under; \n padding-top: 16px;\n margin-bottom: 100px;\n}\n\n.terminal {\n line-height: 1em;\n overflow: scroll;\n padding: 10px; \n color: #00FF41;\n margin: 0px;\n background-color: #151515;\n}\n\n.small-image {\n width: 100%;\n}\n\n.post-date {\n font-size: 17px;\n text-transform: uppercase;\n font-weight: bold;\n color: rgba(0, 0, 0, 0.5);\n}\n\n.post-desc {\n color: rgba(0, 0, 0, .7);\n padding: 10px;\n font-weight: lighter;\n}\n\np.post-excerpt {\n margin-top: 0;\n padding-top: 10px;\n}\n\n\n"
"$normal-text-color: #444444;\n$nav-link-color: #333;\n$nav-link-hover-color: black;\n$link-color: #47a;\n$visited-link-color: #941452;\n\n$last-p-padd: 1.5em;\n$nav-padd: 1em;\n$line-under: 1px solid #aaa; \n\nbody {\n background-color: #fefefe;\n padding: 15px;\n font-family: -apple-system, helvetica, arial, sans-serif;\n}\n#wrapper {\n max-width: 800px;\n margin: auto;\n color: $normal-text-color;\n font-size: 14px;\n}\n#main-name {\n color: rgba(0, 0, 0, 0.8);\n}\n\nli {\n line-height: 1.5em;\n}\n\nh1 {\n font-size: 2.5em;\n}\nh2 {\n font-size: 2.0em;\n}\nh3 {\n font-size: 1.6em;\n}\nh4 {\n font-size: 1.3em;\n}\nh5 {\n font-size: 1.1em;\n}\na {\n text-decoration: underline;\n color: $link-color;\n} \na:visited {\n color: $visited-link-color;\n}\na.nav-link,\na.post-title-link {\n color: $nav-link-color;\n text-decoration: none;\n}\na.citation-link {\n text-decoration: none;\n}\n\n#img-wrapper img {\n margin-bottom: 10px;\n}\n\n#img-wrapper label {\n margin-left: 10px;\n}\n\nlabel {\n font-size: 12px;\n}\n\n#menu,\nlabel[for=\"menu\"]{\n display: none;\n}\n\nnav {\n padding: $nav-padd 0px;\n margin: 0px;\n}\nnav a:first-of-type {\n margin-left: 0;\n}\nnav a {\n margin: 1em;\n color: $nav-link-color;\n font-weight: bold;\n font-style: none;\n}\n/* TODO: Does not work */\n.on-page {\n color: #000;\n}\nnav a:hover {\n text-decoration: underline; \n}\n\nli {\n margin: .5em;\n}\n\n#main-img {\n width: 100%;\n}\np {\n font-size: 15px;\n line-height: 1.5;\n padding: .1em 0;\n}\n.line-under {\n padding-bottom: $last-p-padd;\n border-bottom: $line-under;\n}\n.article a:hover {\n color: rgba(0, 0, 0, 0.5);\n}\n\ntable,\ntable tr,\ntable td,\ntable th{\n border: 1px solid rgba(0, 0, 0, 0.5);\n border-collapse: collapse;\n padding: 5px;\n font-weight: normal;\n}\ntable th {\n font-weight: bold;\n}\ntable {\n width: 75%;\n margin: auto;\n}\n\ntable.post-list,\ntable.post-list tr,\ntable.post-list td {\n width: 100%;\n border: none;\n padding-left: 0;\n}\nimg {\n display: block;\n width: 55%;\n margin-left: auto;\n margin-right: auto;\n}\n\nblockquote {\n font-style: italic;\n}\n\n@media screen and (max-width: 600px){\n #menu,\n label[for=\"menu\"]{\n display: inline-block;\n font-size: 20px;\n }\n body {\n width: 90%;\n }\n #info {\n margin: 0 7px;\n }\n .menu-content {\n max-height: 0;\n overflow: hidden;\n }\n nav {\n width: 100%;\n }\n nav a {\n display: block;\n padding-left: 0;\n margin-left: 0;\n }\n input#menu{\n display: none;\n }\n input:checked ~ .menu-content {\n max-height: 100%;\n border-bottom: $line-under;\n color: red;\n }\n}\n\n.contact-info {\n width: 90%;\n margin: auto;\n word-wrap: break-word;\n}\n.contact-info p {\n margin: 7px;\n padding: 0;\n}\n\n.mono {\n font-family: monospace;\n}\n\n.bold {\n font-weight: bold;\n}\n\nsup {\n margin: 0;\n padding: 0;\n}\n\nfigcaption {\n margin-top: 10px;\n font-size: .8em;\n text-decoration: italic;\n}\n\nfooter {\n border-top: $line-under; \n padding-top: 16px;\n margin-bottom: 100px;\n}\n\n.terminal {\n line-height: 1em;\n overflow: scroll;\n padding: 10px; \n color: #00FF41;\n margin: 0px;\n background-color: #151515;\n}\n\n.file {\n overflow: scroll;\n padding: 10px;\n margin: 0px;\n line-height: 1.2em;\n background-color: #dfdfdf;\n color: #000;\n}\n\n.small-image {\n width: 100%;\n}\n\n.post-date {\n font-size: 17px;\n text-transform: uppercase;\n font-weight: bold;\n color: rgba(0, 0, 0, 0.5);\n}\n\n.post-desc {\n color: rgba(0, 0, 0, .7);\n padding: 10px;\n font-weight: lighter;\n}\n\np.post-excerpt {\n margin-top: 0;\n padding-top: 10px;\n}\n\n\n"
],
"names": [],
"mappings": "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"
"mappings": "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"
}

@ -28,6 +28,18 @@
<table class="post-list">
<tr>
<td>
<h3 class="post-title"><a class="post-title-link" href="/2020/08/16/django-deployment.html">How to Solve The Django Deployment Puzzle</a></h2>
<span class="post-date">16 August 2020</span>
<div class="post-excerpt"><p>A few days ago I had a Django project I wanted to put on a real server.
This project is still in its infancy, but I thought it would be nice to put it on my resume and show my friends.
Little did I know the headache coming my way.
Here are some tips to help you not make the same mistakes as me.</p>
</div>
</td>
</tr>
<tr>
<td>
<h3 class="post-title"><a class="post-title-link" href="/2020/08/15/openbsd1.html">BSD Journey, Part 1</a></h2>

@ -1,4 +1,124 @@
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.0.0">Jekyll</generator><link href="http://localhost:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://localhost:4000/" rel="alternate" type="text/html" /><updated>2020-08-15T15:40:55+00:00</updated><id>http://localhost:4000/feed.xml</id><entry><title type="html">BSD Journey, Part 1</title><link href="http://localhost:4000/2020/08/15/openbsd1.html" rel="alternate" type="text/html" title="BSD Journey, Part 1" /><published>2020-08-15T00:00:00+00:00</published><updated>2020-08-15T00:00:00+00:00</updated><id>http://localhost:4000/2020/08/15/openbsd1</id><content type="html" xml:base="http://localhost:4000/2020/08/15/openbsd1.html">&lt;p&gt;As Linux becomes controlled by corporate sponsors and becomes more full of proprietary blobs, drivers, and even closed-source software like Steam,
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.0.0">Jekyll</generator><link href="http://localhost:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://localhost:4000/" rel="alternate" type="text/html" /><updated>2020-08-18T23:00:11+00:00</updated><id>http://localhost:4000/feed.xml</id><entry><title type="html">How to Solve The Django Deployment Puzzle</title><link href="http://localhost:4000/2020/08/16/django-deployment.html" rel="alternate" type="text/html" title="How to Solve The Django Deployment Puzzle" /><published>2020-08-16T00:00:00+00:00</published><updated>2020-08-16T00:00:00+00:00</updated><id>http://localhost:4000/2020/08/16/django-deployment</id><content type="html" xml:base="http://localhost:4000/2020/08/16/django-deployment.html">&lt;p&gt;A few days ago I had a Django project I wanted to put on a real server.
This project is still in its infancy, but I thought it would be nice to put it on my resume and show my friends.
Little did I know the headache coming my way.
Here are some tips to help you not make the same mistakes as me.&lt;/p&gt;
&lt;h3 id=&quot;asgi-servers&quot;&gt;ASGI Servers&lt;/h3&gt;
&lt;p&gt;Because my project used the ASGI (Asynchronous webServer Gateway Interface),
I needed to find a good production ASGI server to handle all the incoming requests.
The best thing I found was &lt;a href=&quot;http://www.uvicorn.org/&quot;&gt;uvicorn&lt;/a&gt;.
It focuses on speed, which is a priority, especially when using the ASGI protocol.&lt;/p&gt;
&lt;p&gt;To run uvicorn on the command line for testing purposes, use something like the following:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;
$ uvicorn --reload myapp.asgi:application
&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;--reload&lt;/code&gt; option says to reload the server if any of the files get updated.
This is not recommended in production.
Sadly, I thought this meant I would need to do a hard shutdown of the server process every time I wanted to update.
This turned out to not be the case.&lt;/p&gt;
&lt;h3 id=&quot;workload-managers&quot;&gt;Workload Managers&lt;/h3&gt;
&lt;p&gt;There is another equine-named program called &lt;a href=&quot;https://gunicorn.org/&quot;&gt;gunicorn&lt;/a&gt;
which can hold a number of processes under its control.
An interesting feature of &lt;code class=&quot;highlighter-rouge&quot;&gt;gunicorn&lt;/code&gt; is that it will gracefully switch from an old to a new deployment,
replacing the subprocesses one-by-one and eventually having only the new deployment active on all subprocesses.
The greatest part? Zero down time.
The server keeps any old processes open if there is communication with them,
then shift and new connections to the new deployment.
This was a very cool feature I wanted to take advantage of.&lt;/p&gt;
&lt;p&gt;“Now hold on!” you might protest.
“gunicorn is a WSGI server!” … oh you got me there!
Yes, thats right, &lt;code class=&quot;highlighter-rouge&quot;&gt;gunicorn&lt;/code&gt; is paired with &lt;code class=&quot;highlighter-rouge&quot;&gt;uvicorn&lt;/code&gt; to serve my files.&lt;/p&gt;
&lt;h3 id=&quot;systemd&quot;&gt;systemd&lt;/h3&gt;
&lt;p&gt;Love it or hate it, the majority of Linux distributions use the &lt;code class=&quot;highlighter-rouge&quot;&gt;systemd&lt;/code&gt; init system.
I decided it would be very convenient to have a .service file for my Django application to run automatically at boot.
&lt;code class=&quot;highlighter-rouge&quot;&gt;Systemd&lt;/code&gt; allows me to do this with a file like the following one I stored in &lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/systemd/system/lamegames.service&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;file&quot;&gt;
[Unit]
Description=Gunicorn/Uvicorn (lamegames.io)
[Service]
WorkingDirectory=/home/lame/lamegames.io
Type=simple
RemainAfterExit=yes
ExecStart=/home/lame/lamegames.io/env/bin/gunicorn lamegames.asgi:application -w 2 -k uvicorn.workers.UvicornWorker
ExecStop=/bin/kill -HUP $MAINPID
Restart=always
[Install]
WantedBy=multi-user.target
&lt;/pre&gt;
&lt;h3 id=&quot;nginx&quot;&gt;nginx&lt;/h3&gt;
&lt;p&gt;NGINX (pronounced engine-X) is a performance web server designed for speed and simplicity.
For the front facing side of the site, I do need a production web server like nginx.
Gunicorn simply doesnt need all the features that nginx provides, but I do.
To configure my nginx installation, I used the following few directives to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Redirect most traffic towards the gunicorn server.&lt;/li&gt;
&lt;li&gt;Redirect statically served files (CSS, JS, images) to the directory specified in the STATIC_ROOT variable of my &lt;code class=&quot;highlighter-rouge&quot;&gt;settings.py&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Use TLS to enable https://&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Serving the static files from nginx as opposed to the &lt;code class=&quot;highlighter-rouge&quot;&gt;gunicorn&lt;/code&gt; server is necessary.
Gunicorn and other production A/WSGI web server will not set the proper MIME type over TLS.
This will cause your browser to not load the Javascript/CSS.&lt;/p&gt;
&lt;p&gt;This is the important part of my nginx config.&lt;/p&gt;
&lt;pre class=&quot;file&quot;&gt;
server {
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# these two lines ensure that WebSocket, and HTTP2 connection are forwarded correctly
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection &quot;Upgrade&quot;;
proxy_redirect off;
proxy_buffering off;
# this forwards all traffic to the local server on port 8000
proxy_pass http://localhost:8000;
}
# This forwards all static requests to Django's STATIC_ROOT set in settings.py; it is generated using the collectstatic command.
location /static {
autoindex on;
alias /home/lame/lamegames.io/static_generated;
}
}
&lt;/pre&gt;
&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;/h3&gt;
&lt;p&gt;After all that, I was able to do the following:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;
# systemctl enable lamegames
&lt;/pre&gt;
&lt;p&gt;This enabled my &lt;code class=&quot;highlighter-rouge&quot;&gt;gunicorn&lt;/code&gt; server to run once the server started.
NGINX is that way be default.&lt;/p&gt;
&lt;p&gt;And tada! You now have a working Django project on a production server!&lt;/p&gt;
&lt;h4 id=&quot;notes&quot;&gt;Notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;If using ws:// websockets, change them to wss:// for secure web sockets.&lt;/li&gt;
&lt;li&gt;Make sure to use channels.routing.get_default_application() instead of django.get_asgi_application() if yourre wanting to use channels/redis WebSockets.&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><summary type="html">A few days ago I had a Django project I wanted to put on a real server. This project is still in its infancy, but I thought it would be nice to put it on my resume and show my friends. Little did I know the headache coming my way. Here are some tips to help you not make the same mistakes as me.</summary></entry><entry><title type="html">BSD Journey, Part 1</title><link href="http://localhost:4000/2020/08/15/openbsd1.html" rel="alternate" type="text/html" title="BSD Journey, Part 1" /><published>2020-08-15T00:00:00+00:00</published><updated>2020-08-15T00:00:00+00:00</updated><id>http://localhost:4000/2020/08/15/openbsd1</id><content type="html" xml:base="http://localhost:4000/2020/08/15/openbsd1.html">&lt;p&gt;As Linux becomes controlled by corporate sponsors and becomes more full of proprietary blobs, drivers, and even closed-source software like Steam,
One may wonder if there are other options out there.
For me, somebody that is intensely interested in security, there is one option: OpenBSD.&lt;/p&gt;
@ -503,20 +623,4 @@ Although this may annoy your victim it is not dangerous security wise.&lt;/p&gt;
&lt;p&gt;Those last two will ask for permission from the user (if their browser isnt insanely insecure).&lt;/p&gt;
&lt;p&gt;In my next article Ill talk about a website I found which is vulnerable to this attack.
And, show you how you can run your own XSS attack.&lt;/p&gt;</content><author><name></name></author><summary type="html">I found a cross-site scripting (XSS) attack in a well-known quiz hosting website. I disclosed the vulnerability to them years ago, so I thought now might be a good time to write about it.</summary></entry><entry><title type="html">rfi: A Simple Linux utility to get a random file from a directory</title><link href="http://localhost:4000/2020/04/21/rfi.html" rel="alternate" type="text/html" title="rfi: A Simple Linux utility to get a random file from a directory" /><published>2020-04-21T00:00:00+00:00</published><updated>2020-04-21T00:00:00+00:00</updated><id>http://localhost:4000/2020/04/21/rfi</id><content type="html" xml:base="http://localhost:4000/2020/04/21/rfi.html">&lt;p&gt;I made a &lt;a href=&quot;https://lbry.tv/@tait:7/rfi:5&quot;&gt;little video&lt;/a&gt; about this script I wrote:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;
$ rfi
&lt;/pre&gt;
&lt;p&gt;This program gets a random file from your current directory
if you do not specify one;
it gets a random file from the specified directory if you give it one like so:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;
# rfi /etc/wireguard
&lt;/pre&gt;
&lt;p&gt;Which is very useful if you want to start a random VPN configuration :)&lt;/p&gt;
&lt;p&gt;The code, comments, etc. are on the &lt;a href=&quot;https://github.com/TTWNO/scripts&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">I made a little video about this script I wrote:</summary></entry></feed>
And, show you how you can run your own XSS attack.&lt;/p&gt;</content><author><name></name></author><summary type="html">I found a cross-site scripting (XSS) attack in a well-known quiz hosting website. I disclosed the vulnerability to them years ago, so I thought now might be a good time to write about it.</summary></entry></feed>

@ -65,6 +65,10 @@
<lastmod>2020-08-15T00:00:00+00:00</lastmod>
</url>
<url>
<loc>http://localhost:4000/2020/08/16/django-deployment.html</loc>
<lastmod>2020-08-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>http://localhost:4000/2020-04-27-quiz-your-friends-xss.html</loc>
</url>
<url>

@ -0,0 +1,52 @@
---
layout: default
title: "Home"
---
## Tait Hoyem
<div id="img-wrapper">
<img id="main-img" src="/assets/img/banff.jpg" alt="A photot I took of the valley Banff, Alberta sits in">
<label for="main-img">Alberta, Canada</label>
</div>
### About
I am a student at the <a href="https://sait.ca/">Southern Alberta Insitute of Technology (SAIT)</a>.
My fascination lies primarily with operating system internals and systems-level tools.
My goal is to bring the everyday computing environment of Linux/BSD nerds to visually impaired users, and to ensure the saftey, privacy and security of the internet.
Some of my projects reflect this.
I have all of my code projects hosted on [my Github](https://github.com/TTWNO).
### Projects
**[epub-with-pinyin](https://github.com/TTWNO/epub-with-pinyin)** ---
I wrote a program to add Pinyin above Chinese characters in .epub files to assist myself and others learning Mandarin Chinese.
**[chess](https://github.com/TTWNO/chess)** ---
I wrote a command-line chess game in C++. It is compileable on almost any system.
**[tait.tech](https://github.com/TTWNO/tait.tech)** ---
All the code for my website is open source.
**[Napolean](https://github.com/TTWNO/Napolean)** ---
A work-in-progress suite of tools to be used in conjunction with a Raspberry Pi
and camera to produce text files from scanned books.
**[subnetting](https://github.com/TTWNO/subnetting)** ---
A one-night write of a tool to automatically calculate network subnet masks based on required hosts and base IP.
I also ocassionally put content on my [lbry channel](https://lbry.tv/@tait:7), and the [blog I host on this site](/blog/).
#### Ideas
Sometimes I have ideas that I haven't done anything with yet.
Those are [here](/ideas/).
### Contact
You can reach me via email at [tait@tait.tech](mailto:tait@tait.tech)
If you use PGP, [this is my public key](/public-key.asc)

@ -0,0 +1,7 @@
---
layout: default
---
Here are my contact details if you would like to contact me professionally or personally.
{% include contact.html %}

@ -19,6 +19,13 @@ title: "Resume"
{{ education.description }}
{% endfor %}
### Professional Development
{% for education in site.data.proffedu %}
**{{ education.institution }}**---{{ education.level }} / *{{ education.name }}* ({{ education.years }})
{{ education.description }}
{% endfor %}
### Projects
{% for project in site.data.projects %}
**[{{ project.name }}]({{ project.link }})**

Loading…
Cancel
Save