Skip to content

Commit 33285aa

Browse files
committed
Add docker files and instructions
1 parent 7d93603 commit 33285aa

File tree

4 files changed

+44
-263
lines changed

4 files changed

+44
-263
lines changed

Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM python:3.7
2+
RUN pip install pipenv
3+
WORKDIR /app
4+
COPY Pipfile Pipfile.lock ./
5+
RUN pipenv install --system --deploy
6+
COPY . ./
7+
EXPOSE 8000
8+
CMD ./manage.py migrate && ./manage.py runserver 0.0.0.0:8000

README.md

+9-263
Original file line numberDiff line numberDiff line change
@@ -1,265 +1,11 @@
1-
# Deploying Django to DreamHost
1+
# Adding third-party sign-on to a Django site
22

3-
## Presented at [PyYYC][], 2014-01-22
3+
1. Run `docker-compose up --build`
4+
2. Go to the [Meetup Register OAuth Consumer page][oauth_create],
5+
enter anything for the consumer name, and
6+
`http://localhost:8000/oauth/login` for the ‘Redirect URI.’
7+
3. Add `MEETUP_CLIENT_ID` and `MEETUP_CLIENT_SECRET` to
8+
`.django_secrets.json`
9+
4. Visit http://localhost:8000/polls/
410

5-
You have a Django site that works on your local machine, and you want to
6-
run it on the public internet cheaply with a one-line command to
7-
immediately push your local changes to the live site.
8-
9-
Here are the steps used to get the tutorial `polls` Django app in [this
10-
mercurial repository][repo-home] running on a real web server.
11-
12-
[repo-home]: https://bitbucket.org/andrewdotn/deploy_polls
13-
14-
## Feedback and questions are welcome
15-
16-
If you use this and like it, have trouble getting it working, or have
17-
questions about doing more stuff with it, drop me a note! My email is
18-
19-
20-
## Introduction
21-
22-
[PyYYC]: http://www.meetup.com/py-yyc/
23-
24-
Everyone who works with Django has worked their way through the [Django
25-
tutorial][tutorial], building the `polls` app and running it on their local
26-
machine. It’s fun and easy to go from there to building little Django apps
27-
for your own use. But there’s a huge jump to go from running Django sites
28-
on your local machine to running them on the web. Instead of a simple
29-
`manage.py` command, you need to [configure apache modules][wsgi] and stuff
30-
like that, which requires a publicly-accessible webserver that’s properly
31-
configured, secured, and monitored, which can be a lot of work and expense
32-
for a toy site.
33-
34-
[tutorial]: https://docs.djangoproject.com/en/stable/intro/tutorial01/
35-
[wsgi]: https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/modwsgi/
36-
37-
In the old days when people wrote static web sites, deployment was easy:
38-
you’d pay a few dollars a month for a shared web host and rsync your files
39-
over. The host would monitor and secure the server, and if the site had
40-
problems, you’d email support and they’d fix it for you.
41-
42-
It turns out you can still do that with Django: [DreamHost][] is one of the
43-
most popular shared web hosts, and you can run as many Django sites as you
44-
want on it using their standard hosting plan which costs $5.95–$8.95/month
45-
depending on how many months in advance you prepay. For that you get
46-
unlimited domains, unlimited databases, and unlimited bandwidth, full SSH
47-
access to the server, and support when things break.
48-
49-
[DreamHost]: http://www.dreamhost.com/web-hosting/
50-
51-
This is the basic setup I’ve used for about half a dozen Django projects.
52-
It’s allowed me to continuously deploy changes with a minimum of fuss, and
53-
with it you can write a new app and get it running on the web in minutes,
54-
with push-button update ability.
55-
56-
## Preliminary steps
57-
58-
First you need the resources to deploy your site to: a domain, an SSH user,
59-
and a database.
60-
61-
1. Log into the DreamHost panel.
62-
63-
2. Under Domains → Manage Domains, click Add New Domain / Sub-Domain
64-
65-
3. Enter the domain name, select “Create a New User” and enter a username,
66-
and check off the “Passenger (Ruby/Python apps only)” option. Then
67-
click “Fully host this domain.”
68-
69-
4. Under Users → Manage Users, edit the user you just created and change
70-
the User Type to a Shell User. Disallow FTP while you’re in there.
71-
72-
5. Under Goodies → MySQL Databases, create a new database. Pick your own
73-
username and password.
74-
75-
6. It may take a few minutes for SSH to be enabled for the new user. Once
76-
it is, log in and add your SSH public key:
77-
78-
$ mkdir -m 0700 .ssh
79-
$ (umask 0077 && cat > .ssh/authorized_keys)
80-
[paste ~/.ssh/id_rsa.pub from your dev machine]
81-
^D
82-
83-
7. Configure ssh to remember your username by adding lines like this to
84-
`~/.ssh/config`:
85-
86-
Host newdomain.example.org
87-
User newuser
88-
89-
8. Update the `DOMAIN` in `settings.py` to point to this new domain.
90-
91-
## Getting your site running on DreamHost
92-
93-
You’ll need to do some initial setup on the server, and then push your code
94-
to the server.
95-
96-
These steps work with the code in this repository. You can fork this repo,
97-
deploy it yourself, then pull out the `polls` app and add your own. Or, you
98-
can look at the commit history of this repo to see the relatively few
99-
things that were done to `polls` to make it deployable.
100-
101-
1. Download the Python [source tarball][python27], unpack it, and install
102-
it. DreamHost servers have Python already but this gets the latest
103-
version and makes it easier to install additional packages.
104-
105-
$ mkdir src && cd src
106-
$ wget 'http://www.python.org/ftp/python/2.7.6/Python-2.7.6.xz'
107-
$ tar xf Python-2.7.6.xz
108-
$ cd Python-2.7.6
109-
$ nice sh -c './configure --with-system-expat --prefix=$HOME/local \
110-
&& make -j2 && make install'
111-
112-
2. Add `$HOME/local/bin` to your path in `~/.bashrc` and/or
113-
`~/.bash_profile` as needed, then logout and log back in.
114-
115-
3. Download setuptools to `~/src`, unpack it, and install it:
116-
117-
$ cd ~/src
118-
$ curl -LO 'https://pypi.python.org/packages/source/s/setuptools/setuptools-2.1.tar.gz'
119-
$ tar xf setuptools-2.1.tar.gz
120-
$ cd setuptools-2.1
121-
$ python setup.py install
122-
123-
4. Use `easy_install` to install `pip` and `mercurial`.
124-
125-
$ easy_install pip mercurial
126-
127-
5. Set up the mysql configuration file:
128-
129-
(umask 0077 && echo '[client]
130-
password="password"
131-
host="mysql.example.org"
132-
user="username"
133-
database="database_name"' > ~/.my.cnf)
134-
135-
6. Push your code to the server.
136-
137-
On the server:
138-
139-
$ mkdir ~/hg
140-
$ cd ~/hg
141-
$ hg init
142-
143-
Then on your local machine, update `.hg/hgrc` with the new path:
144-
145-
[paths]
146-
default-push = ssh://newdomain.example.org/hg
147-
148-
and run `hg push`.
149-
150-
7. Now run `./manage.py deploy` on your local machine and you’re good to
151-
go!
152-
153-
8. To add a superuser on the server, run
154-
155-
ssh -t newhost.example.org newhost.example.org/code/manage.py createsuperuser
156-
157-
[python27]: http://www.python.org/ftp/python/2.7.6/Python-2.7.6.xz
158-
[pip]: https://pypi.python.org/packages/source/p/pip/pip-1.5.1.tar.gz
159-
160-
## Deploying changes to DreamHost
161-
162-
Run `./manage.py deploy`. That’s it!
163-
164-
## Demo
165-
166-
Andrew logs in to the DreamHost web panel, creates a new subdomain, updates
167-
`DOMAIN` in `settings.py`, waits for DNS to propagate, runs `deploy`, and
168-
immediately gets a deployed website. “Hello world” is added to a page,
169-
`deploy` is run, and the live site picks up the new text.
170-
171-
The actual presentation did not go quite this smoothly, and I sort of
172-
blamed DreamHost, but it was really my forgetting to configure
173-
[`ALLOWED_HOSTS`][ALLOWED_HOSTS] properly.
174-
175-
[ALLOWED_HOSTS]: https://www.djangoproject.com/weblog/2013/feb/19/security/
176-
177-
## Questions
178-
179-
- How scalable is this?
180-
181-
One website I helped set up with this was once linked to by a very
182-
popular blog and started getting around 15 requests/s at which point it
183-
basically fell over. My friend tweaked some things like caching and
184-
moving some things to be served statically instead of dynamically, and
185-
subsequent testing showed that it would be able to stand 30 requests/s.
186-
187-
I think we were using a DreamHost VPS at that point though—if your
188-
site is using tons of CPU or you want better performance, you can move
189-
it from the shared hosting environment at DreamHost to a VPS that you
190-
get root access on for around $50/month extra.
191-
192-
- My site uses a third-party library like `markdown`. How do I deploy
193-
that?
194-
195-
Just add it to `requirements.txt`, commit, and run `manage.py deploy`.
196-
The deploy script automatically installs everything in there.
197-
198-
- What about database migrations?
199-
200-
Add [South][] to `requirements.txt`, and update the `deploy` management
201-
command to pass `--migrate` to `syncdb`, or wait for [Django 1.7][].
202-
203-
[South]: http://south.aeracode.org
204-
[Django 1.7]: https://www.kickstarter.com/projects/andrewgodwin/schema-migrations-for-django
205-
206-
## Next steps
207-
208-
- [Pingdom][] is an awesome web service that checks your website every
209-
minute to make sure it’s up and displaying the right stuff. It has two
210-
great functions with DreamHost: it alerts you to check your code and/or
211-
contact DreamHost support if there’s ever a problem with your site, and
212-
since it visits your site every minute, the Django processes on the
213-
server never time out and you don’t get a delayed load when someone
214-
first visits your low-traffic site.
215-
216-
[Pingdom]: https://www.pingdom.com
217-
218-
- See the [Django Deploying Checklist][deployment-checklist] for other
219-
Django-specific deployment steps.
220-
221-
- See the [Web Operations][] textbook for guidance on keeping your site
222-
running smoothly and professionally, setting up logging, monitoring,
223-
and alerting, tuning your database, and much more.
224-
225-
- See [Continuous Delivery][] for how to build more advanced
226-
high-availability deployment pipelines.
227-
228-
[Web Operations]: http://www.amazon.ca/dp/1449377440
229-
[Continuous Delivery]: http://www.amazon.ca/dp/0321601912
230-
[deployment-checklist]: https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
231-
232-
## Future work
233-
234-
If anyone’s interested, or if I need the functionality myself, here are
235-
some ways that this could be extended:
236-
237-
- This setup doesn’t let your site send email, but DreamHost absolutely
238-
allows you to send email. These instructions could be updated to
239-
include how to set that up.
240-
241-
- Automating database and log file backups. This is made easier by the
242-
fact that DreamHost unix users can install crontabs.
243-
244-
- The deployment command could take a revision argument to support
245-
rollbacks.
246-
247-
- Instead of requiring people to add deployment stuff to individual sites,
248-
the `deploy` command and the stuff it needs could be packaged as its own
249-
[PyPI][] module. Instead of forking this module or reproducing the steps
250-
in the commit history, making a project deployment could be as simple as
251-
adding a module to `requirements.txt` and `INSTALLED_APPS`.
252-
253-
[PyPI]: http://cheeseshop.python.org
254-
255-
- DreamHost actually offers an [API][] that lets you create and edit
256-
domains, users, databases, and email addresses. All the steps in this
257-
document could be totally automated and packaged in a module. That way,
258-
you could just add a new deployment app to the project, and run
259-
something like `./manage.py --deploy --initial newsubdomain.example.org`
260-
to have everything automatically set up for you.
261-
262-
[API]: http://wiki.dreamhost.com/Application_programming_interface
263-
264-
It would be really cool if this grew into something that could automate
265-
initial and continuous deployment of Django apps to different web hosts!
11+
[create]: https://secure.meetup.com/meetup_api/oauth_consumers/create

anoncat

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env python
2+
3+
import argparse
4+
import json
5+
6+
parser = argparse.ArgumentParser()
7+
parser.add_argument('file')
8+
options = parser.parse_args()
9+
10+
with open(options.file, 'r') as f:
11+
data = json.load(f)
12+
13+
for k, v in data.items():
14+
if 'SECRET' in k:
15+
data[k] = '********'
16+
17+
print(json.dumps(data, indent=2))

docker-compose.yml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: "3.7"
2+
3+
services:
4+
app:
5+
build: .
6+
image: pyyyc
7+
ports:
8+
- "8000:8000"
9+
volumes:
10+
- .:/app

0 commit comments

Comments
 (0)