├── architecture.png
├── 2.django-basic-settings
├── uwsgi.conf
├── {PROJECT NAME}.ini
├── nginx.conf
└── README.md
├── 5.utilities-wiki-and-snippets
├── use-sass-for-stylesheet.md
├── use-travis-ci.md
├── use-gulp-as-task-runner.md
├── use-docker-at-mac-os-x.md
├── deploy-aws-lambda-using-zappa.md
├── use-webpack-as-module-bundler.md
├── manage-package-with-npm.md
├── multi-browser-test-by-selenium-grid.md
├── meteor-wiki.md
└── deploy-with-fabric.md
├── 3.django-code-snippets
├── use-redis-to-manage-in-memory-db.md
├── use-celery-to-run-task-asynchronously.md
├── use-pillow-to-process-image.md
├── use-firebase-as-realtime-db.md
├── upload-image-to-cloudinary.md
├── send-mail-with-template.md
├── internationalization.md
└── detect-facebook-deauthorization.md
├── README.md
├── 1.ubuntu-basic-settings
├── .vimrc
└── README.md
└── 4.deploy-django-with-aws
└── README.md
/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ukjin1192/web-stack-wiki-and-snippets/HEAD/architecture.png
--------------------------------------------------------------------------------
/2.django-basic-settings/uwsgi.conf:
--------------------------------------------------------------------------------
1 | # Emperor uWSGI script
2 |
3 | description "uWSGI Emperor"
4 | start on runlevel [2345]
5 | stop on runlevel [06]
6 |
7 | exec uwsgi --master --die-on-term --emperor /etc/uwsgi/vassals/
8 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/use-sass-for-stylesheet.md:
--------------------------------------------------------------------------------
1 | #### Install SASS
2 |
3 | ~~~~
4 | $ sudo apt-get install ruby-full
5 | $ sudo su -c "gem install sass"
6 | ~~~~
7 |
8 |
9 | #### Convert SASS to CSS
10 |
11 | ~~~~
12 | $ sass styles.scss:styles.css
13 | ~~~~
14 |
--------------------------------------------------------------------------------
/3.django-code-snippets/use-redis-to-manage-in-memory-db.md:
--------------------------------------------------------------------------------
1 | #### `views.py`
2 |
3 | ~~~~
4 | from django.core.cache import cache
5 | from django_redis import get_redis_connection
6 |
7 |
8 | con = get_redis_connection('default')
9 |
10 | cache.set('foo', 'bar', timeout=10) # Create cache
11 | cache.get('foo') # Retrieve cache value
12 | con.expire(':1:foo', 100) # Extend cache TTL
13 | cache.delete('foo') # Delete cache
14 | ~~~~
15 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/use-travis-ci.md:
--------------------------------------------------------------------------------
1 | #### Sign up
2 |
3 | - Visit Travis CI
4 | - Sign up with Github account
5 |
6 | #### Add Travis CI to repository
7 |
8 | - Go to profile page
9 | - Flick the repository switch on
10 | - Add `.travis.yml` to the root of your repository
11 | - Language example here
12 | - Add `https://secure.travis-ci.org/{GITHUB USERNAME}/{REPOSITORY NAME}.png` to your `README.md`
13 | - `git push` and check at Github repository
14 |
--------------------------------------------------------------------------------
/3.django-code-snippets/use-celery-to-run-task-asynchronously.md:
--------------------------------------------------------------------------------
1 | #### `cron.py`
2 |
3 | ~~~~
4 | from celery import task
5 |
6 |
7 | @task()
8 | def sample_async_task(*args, **kwargs):
9 | return None
10 | ~~~~
11 |
12 |
13 | #### `views.py`
14 |
15 | ~~~~
16 | from cron import sample_async_task
17 |
18 |
19 | # Run task asynchronously with celery after 1 second
20 | sample_async_task.apply_async(
21 | args=[
22 | 'foo_1',
23 | 'foo_2',
24 | ],
25 | kwargs={
26 | 'foo_3': 'bar',
27 | 'foo_4': 'bar',
28 | },
29 | countdown=1
30 | )
31 | ~~~~
32 |
--------------------------------------------------------------------------------
/3.django-code-snippets/use-pillow-to-process-image.md:
--------------------------------------------------------------------------------
1 | #### `utilities.py`
2 |
3 | ~~~~
4 | from PIL import ImageOps
5 |
6 |
7 | def process_image(image_file):
8 | """"
9 | Process image file
10 | """"
11 | file_extension = image_file.content_type.split('/')[1]
12 |
13 | if file_extension is not in ['png', 'jpeg', 'bmp', 'gif']:
14 | return None
15 |
16 | width, height = get_image_dimensions(raw_file)
17 |
18 | size = (100, 70)
19 | thumbnail_image = ImageOps.fit(image_file, size, ImageObj.ANTIALIAS)
20 |
21 | return None
22 | ~~~~
23 |
24 |
25 | #### `views.py`
26 |
27 | ~~~~
28 | from utilities import process_image
29 |
30 |
31 | for raw_file in request.FILES.getlist('file'):
32 | process_image(raw_file)
33 | ~~~~
34 |
--------------------------------------------------------------------------------
/2.django-basic-settings/{PROJECT NAME}.ini:
--------------------------------------------------------------------------------
1 | [uwsgi]
2 | ## variables
3 | username = root
4 | projectname = {PROJECT NAME}
5 | projectpath = {PROEJECT PATH}
6 |
7 | ## config
8 | uid = www-data
9 | gid = www-data
10 | vhost = true
11 | # master
12 | master = true
13 | # maximum number of processes (usually, 2 * cores. More time consuming tasks, less processes(=workers) are required)
14 | processes = 2
15 | # respawn processes taking more than 20 seconds
16 | harakiri = 20
17 | # the socket (use the full path to be safe)
18 | socket = /dev/shm/%(projectname).sock
19 | # with appropriate permissions
20 | chmod-socket = 775
21 | enable-threads = true
22 | # Project path
23 | chdir = %(projectpath)
24 | # Django's wsgi file
25 | module = %(projectname).wsgi
26 | # clear environment on exit
27 | vacuum = true
28 | max-request = 5000
29 | daemonize = %(projectpath)/logs/uwsgi.log
30 | pidfile = %(projectpath)/logs/uwsgi.pid
31 |
--------------------------------------------------------------------------------
/3.django-code-snippets/use-firebase-as-realtime-db.md:
--------------------------------------------------------------------------------
1 | #### Pre-settings at firebase
2 |
3 | - Make new repository at Firebase
4 | - Check `repository URL` and `API secret code`
5 |
6 |
7 | #### Install firebase
8 |
9 | ~~~~
10 | $ pip install requests
11 | $ pip install python-firebase
12 | ~~~~
13 |
14 |
15 | #### `settings.py`
16 |
17 | ~~~~
18 | FIREBASE_USERNAME = '{USERNAME}'
19 | FIREBASE_REPO_URL = '{REPOSITORY URL}'
20 | FIREBASE_API_SECRET = '{API SECRET CODE}'
21 | ~~~~
22 |
23 |
24 | #### `utilities.py`
25 |
26 | ~~~~
27 | from firebase import firebase
28 |
29 | FIREBASE_USERNAME = getattr(settings, 'FIREBASE_USERNAME')
30 | FIREBASE_REPO_URL = getattr(settings, 'FIREBASE_REPO_URL')
31 | FIREBASE_API_SECRET = getattr(settings, 'FIREBASE_API_SECRET')
32 |
33 | authentication = firebase.FirebaseAuthentication(FIREBASE_API_SECRET, FIREBASE_USERNAME, True, True)
34 | firebase_obj = firebase.FirebaseApplication(FIREBASE_REPO_URL, authentication)
35 |
36 |
37 | def update_firebase_database(permalink, key, value):
38 | """
39 | Update Firebase DB
40 | """
41 | firebase_obj.put(permalink, key, value)
42 |
43 | return None
44 | ~~~~
45 |
46 |
47 | #### `views.py`
48 |
49 | ~~~~
50 | from utilities import update_firebase_database
51 |
52 |
53 | update_firebase_database(
54 | '/fpp/',
55 | 'bar',
56 | 0
57 | )
58 | ~~~~
59 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/use-gulp-as-task-runner.md:
--------------------------------------------------------------------------------
1 | #### Install gulp
2 |
3 | ~~~~
4 | $ cd {PROJECT PATH}
5 | # Remove old version
6 | $ npm rm gulp --global
7 | $ npm install gulp-cli --global
8 | $ npm init
9 | $ npm install gulp --save-dev
10 | ~~~~
11 |
12 |
13 | #### Minify(Uglify) javascript files
14 |
15 | ~~~~
16 | $ npm install gulp-uglify --save-dev
17 | $ vi gulpfile.js
18 |
19 | var gulp = require('gulp');
20 | var uglify = require('gulp-uglify');
21 |
22 | // Minify javascript files
23 | gulp.task('uglify', function () {
24 | return gulp.src('src/*.js')
25 | .pipe(uglify())
26 | .pipe(gulp.dest('dist'));
27 | });
28 |
29 | // Enroll watch task
30 | gulp.task('watch', function () {
31 | gulp.watch('src/*.js', ['uglify']);
32 | });
33 |
34 | // Run watch task as default
35 | gulp.task('default', ['uglify', 'watch']);
36 |
37 | $ gulp
38 | ~~~~
39 |
40 |
41 | #### Convert SASS to CSS
42 |
43 | ~~~~
44 | $ npm install gulp-sass --save-dev
45 | $ vi gulpfile.js
46 |
47 | var gulp = require('gulp');
48 | var sass = require('gulp-sass');
49 |
50 | // Convert SASS to CSS
51 | gulp.task('styles', function() {
52 | gulp.src('sass/**/*.scss')
53 | .pipe(sass().on('error', sass.logError))
54 | .pipe(gulp.dest('./css/'));
55 | });
56 |
57 | // Enroll watch task
58 | gulp.task('watch', function () {
59 | gulp.watch('sass/**/*.scss', ['styles']);
60 | });
61 |
62 | // Run watch task as default
63 | gulp.task('default', ['styles', 'watch']);
64 |
65 | $ gulp
66 | ~~~~
67 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/use-docker-at-mac-os-x.md:
--------------------------------------------------------------------------------
1 | #### Install docker
2 |
3 | - Download docker at this site
4 | - Docker will be installed with VirtualBox
5 |
6 |
7 | #### Docker command
8 |
9 | ~~~
10 | # Search image
11 | $ docker search {IMAGE NAME}
12 |
13 | # Download image
14 | $ docker pull {IMAGE NAME}
15 |
16 | # List-up whole image
17 | $ docker images
18 |
19 | # Remove image
20 | $ docker rmi {IMAGE NAME}
21 |
22 | # Create container
23 | $ docker run -i -t -p {EXPOSING PORT} --name {CONTAINER NAME} {IMAGE NAME:TAG} {COMMAND(e.g. /bin/bash)}
24 |
25 | # List-up whole container
26 | $ docker ps -a
27 |
28 | # Rename container
29 | $ docker rename {ORIGINAL CONTAINER NAME} {NEW CONTAINER NAME}
30 |
31 | # Remove container
32 | $ docker rm {CONTAINER NAME}
33 |
34 | # Re-run stopped container
35 | $ docker start {CONTAINER NAME}
36 |
37 | # Restart container
38 | $ docker restart {CONTAINER NAME}
39 |
40 | # Attach container
41 | $ docker attach {CONTAINER NAME}
42 |
43 | # Stop container
44 | $ docker stop {CONTAINER NAME}
45 |
46 | # Create image
47 | $ vi Dockerfile [Fill out contents]
48 | $ docker build --tag {IMAGE NAME}:{TAG}
49 |
50 | # Create image from existing container
51 | $ docker commit {CONTAINER NAME} {NEW IMAGE NAME}:{TAG}
52 |
53 | # Check exposing port of container
54 | $ docker port {CONTAINER NAME}
55 |
56 | # Detach container
57 | (In container) Ctrl-P + Ctrl-Q
58 |
59 | # Start new shell on running container
60 | $ docker exec -it {CONTAINER NAME} /bin/bash
61 | ~~~~
62 |
--------------------------------------------------------------------------------
/3.django-code-snippets/upload-image-to-cloudinary.md:
--------------------------------------------------------------------------------
1 | #### Pre-settings at cloudinary
2 |
3 | - Enroll new application
4 | - Check API key and API secret code at Cloudinary
5 |
6 |
7 | #### Install cloudinary
8 |
9 | ~~~~
10 | $ pip install cloudinary
11 | ~~~~
12 |
13 |
14 | #### `settings.py`
15 |
16 | ~~~~~
17 | CLOUDINARY_API_KEY = '576224373763765'
18 | CLOUDINARY_API_SECRET = 'aiVax8O_I2SfPe7ufT-Uy9GI7r4'
19 | ~~~~~
20 |
21 |
22 | #### `utilities.py`
23 |
24 | ~~~~
25 | import cloudinary
26 | import cloudinary.uploader
27 |
28 | CLOUDINARY_API_KEY = getattr(settings, 'CLOUDINARY_API_KEY')
29 | CLOUDINARY_API_SECRET = getattr(settings, 'CLOUDINARY_API_SECRET')
30 |
31 | cloudinary.config(
32 | cloud_name = '{YOUR APP NAME}',
33 | api_key = CLOUDINARY_API_KEY,
34 | api_secret = CLOUDINARY_API_SECRET
35 | )
36 |
37 |
38 | def upload_image_to_cloudinary(image_obj):
39 | """
40 | Updload image to Cloudinary and return media url
41 | """
42 | # Check file type is image
43 | if image_obj.content_type.split('/')[0] != 'image':
44 | return ''
45 |
46 | file_size = image_obj._size
47 | width, height = get_image_dimensions(image_obj)
48 |
49 | cloudinary_obj = cloudinary.uploader.upload(image_obj, width=width, height=height)
50 |
51 | return cloudinary_obj['secure_url']
52 | ~~~~
53 |
54 |
55 | #### `views.py`
56 |
57 | ~~~~
58 | from utilities import upload_image_to_cloudinary
59 |
60 |
61 | if 'image' in request.FILES:
62 | image_url = upload_image_to_cloudinary(request.FILES['image'])
63 | ~~~~
64 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/deploy-aws-lambda-using-zappa.md:
--------------------------------------------------------------------------------
1 | #### Install AWS CLI
2 |
3 | ~~~~
4 | $ pip install awscli --upgrade
5 | ~~~~
6 |
7 | #### Create IAM
8 |
9 | - http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
10 | - Permission : `AdministratorAccess`
11 |
12 | #### Set AWS configuration at the local instance
13 |
14 | ~~~~
15 | $ aws configure
16 | AWS Access Key ID [None]: {BLAH}
17 | AWS Secret Access Key [None]: {BLAH}
18 | Default region name [None]: ap-northeast-2 // SEOUL
19 | Default output format [None]: json
20 | ~~~~
21 |
22 | - Check configuration
23 |
24 | ~~~~
25 | $ cat ~/.aws/credentials
26 | $ cat ~/.aws/config
27 | ~~~~
28 |
29 | #### Clone python project
30 |
31 | ~~~~
32 | $ git clone {GIT REPOSITORY}
33 | $ cd {PROJECT DIRECTORY}
34 | ~~~~
35 |
36 | #### Install virtualenv and install python packages
37 |
38 | ~~~~
39 | $ pip install virtualenv --upgrade
40 | $ virtualenv {VIRTUALENV NAME}
41 | $ source {VIRTUALENV NAME}/bin/activate
42 | $ pip install -r pip-requirements.txt
43 | $ pip install zappa
44 | ~~~~
45 |
46 | #### Deploy AWS lambda using Zappa
47 |
48 | ~~~~
49 | $ zappa init
50 | What do you want to call this environment (default 'dev'): dev // Environment = Stage
51 | What do you want call your bucket? (default 'zappa-xi82x3v32'):
52 | Where is your app's function?: {PYTHON_MODULE.FUNCTION_NAME}
53 | Would you like to deploy this application globally? (default 'n') [y/n/(p)rimary]: n
54 | Does this look okay? (default 'y') [y/n]: y
55 | $ vi zappa_settings.json
56 | "keep_warm": false,
57 | $ zappa deploy {STAGE NAME}
58 | ~~~~
59 |
60 | - After every code updates,
61 |
62 | ~~~~
63 | $ zappa update {STAGE NAME}
64 | ~~~~
65 |
66 | - Using local variables : https://github.com/Miserlou/Zappa#setting-environment-variables
67 | - Search logs at CloudWatch
68 | - Metric Filters
69 | - Expire Events After
70 |
--------------------------------------------------------------------------------
/3.django-code-snippets/send-mail-with-template.md:
--------------------------------------------------------------------------------
1 | #### Edit security setting of account
2 |
3 | - Visit here
4 | - Click `Continue`
5 | - Visit here
6 | - Update to `Allow`
7 |
8 | #### `settings.py`
9 |
10 | ~~~~
11 | EMAIL_HOST = 'smtp.gmail.com'
12 | EMAIL_HOST_USER = '{ADMIN GMAIL ACCOUNT}'
13 | EMAIL_HOST_PASSWORD = '{PASSWORD}'
14 | EMAIL_PORT = 587
15 | EMAIL_USE_TLS = True
16 | ~~~~
17 |
18 |
19 | #### `utilities.py`
20 |
21 | ~~~~
22 | from django.core.mail import EmailMultiAlternatives
23 | from django.template import Context
24 | from django.template.loader import get_template
25 |
26 |
27 | def send_mail_with_template(subject, template_name, user_from, *user_to, **dict_var):
28 | """
29 | Send mail with template
30 | """
31 | plaintext = get_template('email/email.txt')
32 | htmly = get_template(template_name)
33 | d = Context(dict_var)
34 |
35 | text_content = plaintext.render(d)
36 | html_content = htmly.render(d)
37 |
38 | msg = EmailMultiAlternatives(
39 | subject,
40 | text_content,
41 | user_from,
42 | user_to
43 | )
44 | msg.attach_alternative(html_content, 'text/html')
45 | msg.send()
46 |
47 | return None
48 | ~~~~
49 |
50 |
51 | #### `views.py`
52 |
53 | ~~~~
54 | from utilities import send_mail_with_template
55 |
56 |
57 | send_mail_with_template(
58 | 'MAIL TITLE',
59 | 'email_content.html',
60 | '{ADMIN GMAIL ACCOUNT}',
61 | 'user_to_1@domain.com', 'user_to_2@domain.com', ...,
62 | name='Tim', year=2015
63 | )
64 | ~~~~
65 |
66 | #### `templates/email.txt`
67 |
68 | ~~~~
69 | ANY TEXT HERE
70 | ~~~~
71 |
72 |
73 | #### `templates/email_content.html`
74 |
75 | ~~~~
76 |
77 | Hello, {{ name }}!
78 | You've got mail for year {{ year }}!
79 |
80 | ~~~~
81 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/use-webpack-as-module-bundler.md:
--------------------------------------------------------------------------------
1 | #### Install Webpack
2 |
3 | ~~~~
4 | $ npm install webpack --global
5 | $ npm install webpack --save-dev
6 | ~~~~
7 |
8 |
9 | #### Install packages for example and create modules
10 |
11 | ~~~~
12 | $ npm install lodash jquery --save
13 | $ cd {PATH TO JS DIRECTORY}
14 | $ vi module-foo.js
15 |
16 | 'use strict';
17 |
18 | var _ = require('lodash');
19 |
20 | module.exports = function sumList() {
21 | return _.sum(arguments);
22 | };
23 |
24 | $ vi module-bar.js
25 |
26 | 'use strict';
27 |
28 | var $ = require('jquery');
29 |
30 | module.exports = function helloWorld() {
31 | $('#hello-world').html('Hello world');
32 | };
33 | ~~~~
34 |
35 |
36 | #### Create entry file and template
37 |
38 | ~~~~
39 | $ vi index.js
40 |
41 | 'use strict'
42 |
43 | var foo = require('./foo');
44 | var bar = require('./bar');
45 |
46 | console.log(foo(1,2,3,4));
47 | bar();
48 |
49 | $ vi index.html
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ~~~~
60 |
61 |
62 | #### Create configuration file and bundle it
63 |
64 | ~~~~
65 | $ vi webpack.config.js
66 |
67 | 'use strict';
68 |
69 | var webpack = require('webpack');
70 |
71 | module.exports = {
72 | entry: {
73 | bundle: './index.js',
74 | vendor: ['jquery', 'lodash'],
75 | },
76 | output: {
77 | path: './dist/',
78 | filename: '[name].js',
79 | },
80 | plugins: [
81 | new webpack.optimize.CommonsChunkPlugin(
82 | 'vendor',
83 | 'vendor.bundle.js'
84 | )
85 | ],
86 | resolve: {
87 | extensions: ['', '.js', '.es6']
88 | },
89 | };
90 |
91 | $ webpack
92 | ~~~~
93 |
--------------------------------------------------------------------------------
/3.django-code-snippets/internationalization.md:
--------------------------------------------------------------------------------
1 | #### Basic settings
2 |
3 | ~~~~
4 | $ apt-get install gettext
5 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
6 |
7 | ...
8 | LANGUAGE_CODE = 'ko'
9 | ugettext = lambda s: s
10 | LANGUAGES = (
11 | ('ko', ugettext('Korean')),
12 | ('en', ugettext('English')),
13 | )
14 | LOCALE_PATHS = (
15 | ROOT_DIR + '/locale/', # /var/www/mysite.com/locale
16 | )
17 | USE_I18N = True
18 | USE_L10N = True
19 | ...
20 | MIDDLEWARE_CLASSES = (
21 | 'django.contrib.sessions.middleware.SessionMiddleware',
22 | 'django.middleware.locale.LocaleMiddleware',
23 | 'django.middleware.common.CommonMiddleware',
24 | ...
25 | )
26 | # TEMPLATE_CONTEXT_PROCESSORS have django.core.context_processors.i18n as default
27 | ~~~~
28 |
29 | #### Internationalization in template code
30 |
31 | ~~~~
32 | $ vi {PROJECT PATH}/{PROJECT NAME}/templates/test.html
33 |
34 | {% load i18n %}
35 | ...
36 | {% trans "Hello" %}
37 | ...
38 |
39 | $ cd {PROJECT PATH}
40 | $ django-admin.py makemessages -l {LOCALE NAME}
41 | ~~~~
42 |
43 |
44 | #### Internationalization in javascript code
45 |
46 | ~~~~
47 | $ vi {PROJECT PATH}/{PROJECT NAME}/urls.py
48 |
49 | from django.views.i18n import javascript_catalog
50 |
51 | js_info_dict = {
52 | 'packages': ('your.app.package',),
53 | }
54 |
55 | urlpatterns = [
56 | url(r'^jsi18n/$', javascript_catalog, js_info_dict),
57 | ]
58 |
59 | $ vi {PROJECT PATH}/{PROJECT NAME}/templates/test.html
60 |
61 |
64 |
65 | $ cd {PROJECT PATH}
66 | $ django-admin.py makemessages -d djangojs -l {LOCALE NAME}
67 | ~~~~
68 |
69 |
70 | #### Localization
71 |
72 | ~~~~
73 | $ vi {PROJECT PATH}/locale/{LOCALE NAME}/LC_MESSAGES/django.po
74 |
75 | msgid "Hello"
76 | msgstr "안녕"
77 |
78 | $ cd {PROJECT PATH}
79 | $ django-admin.py compilemessages
80 | ~~~~
81 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/manage-package-with-npm.md:
--------------------------------------------------------------------------------
1 | #### Install npm
2 |
3 | - 16.04 (Install `nodejs-legacy` to use `node` command instead of `nodejs`)
4 |
5 | ~~~~
6 | $ apt-get update
7 | #
8 | $ apt-get install nodejs npm nodejs-legacy
9 | ~~~~
10 |
11 | - 18.04
12 |
13 | ~~~~
14 | $ sudo apt install curl
15 | $ curl -sL https://deb.nodesource.com/setup_8.x | sudo bash -
16 | $ sudo apt install nodejs
17 | ~~~~
18 |
19 |
20 | #### npm command
21 |
22 | ~~~~
23 | # Install packages with package.json
24 | $ cd {PATH TO package.json}
25 | $ npm install
26 |
27 | # Install package globally
28 | $ npm install {MODULE NAME}@{VERSION} --global
29 |
30 | # Install package to run this application
31 | $ npm install {MODULE NAME}@{VERSION} --save
32 |
33 | # Install package for development purpose (e.g. unit test or minification)
34 | $ npm install {MODULE NAME}@{VERSION} --save-dev
35 |
36 | # Uninstall packaes - same with install command
37 | $ npm uninstall {MODULE NAME}@{VERSION} --global
38 | $ npm uninstall {MODULE NAME}@{VERSION} --save
39 | $ npm uninstall {MODULE NAME}@{VERSION} --save-dev
40 |
41 | # Check version of module
42 | $ npm list {MODULE NAME}
43 |
44 | # Check list of whole module
45 | $ npm ls --depth=0
46 | ~~~~
47 |
48 |
49 | #### Package management
50 |
51 | - Initiate package management
52 |
53 | ~~~~
54 | $ cd {PROJECT PATH}
55 | $ npm init [Put information]
56 | $ npm install --save lodash
57 | ~~~~
58 |
59 | - Recommend to add `node_modules/` to `.gitignore`
60 | - Example of `package.json`
61 |
62 | ~~~~
63 | {
64 | "name": "mysite.com",
65 | "version": "0.0.0",
66 | "description": "",
67 | "main": "index.js",
68 | "scripts": {
69 | "test": "echo \"Error: no test specified\" && exit 1"
70 | },
71 | "author": "",
72 | "license": "BSD-2-Clause",
73 | "dependencies": {
74 | "lodash": "~3.10.1"
75 | }
76 | }
77 | ~~~~
78 |
79 |
80 | #### Node style programming example
81 |
82 | ~~~~
83 | $ vi index.js
84 |
85 | 'use strict';
86 |
87 | var _ = require('lodash');
88 |
89 | module.exports = function helloWorld() {
90 | _.times(10, function (index) {
91 | console.log('[' + index + '] hello world!');
92 | });
93 | };
94 |
95 | $ vi test.js
96 |
97 | 'use strict';
98 |
99 | var helloWorld = require('./');
100 | helloWorld();
101 |
102 | $ node test.js
103 | ~~~~
104 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/multi-browser-test-by-selenium-grid.md:
--------------------------------------------------------------------------------
1 | #### Get Selenium grid
2 |
3 | - Visit Selenium website
4 | - Download `Selenium Standalone Server`
5 |
6 |
7 | #### `SeleniumTest.java`
8 |
9 | ~~~~
10 | import java.net.URL;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | import org.openqa.selenium.By;
14 | import org.openqa.selenium.Dimension;
15 | import org.openqa.selenium.JavascriptExecutor;
16 | import org.openqa.selenium.Platform;
17 | import org.openqa.selenium.Point;
18 | import org.openqa.selenium.WebDriver;
19 | import org.openqa.selenium.remote.DesiredCapabilities;
20 | import org.openqa.selenium.remote.RemoteWebDriver;
21 |
22 | public class SeleniumTest {
23 |
24 | public static void main(String[] args) throws Exception {
25 |
26 | // Set web driver
27 | String baseURL = 'http://mysite.com';
28 | String nodeURL = 'http://127.0.0.1:5566/wd/hub';
29 |
30 | DesiredCapabilities capability = DesiredCapabilities.iphone();
31 | capability.setBrowserName("firefox");
32 | capability.setPlatform(Platform.VISTA);
33 |
34 | WebDriver driver = new RemoteWebDriver(new URL(nodeURL), capability);
35 |
36 | // Wait 3 seconds if element is not loaded yet
37 | driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
38 |
39 | // Set browser size
40 | driver.manage().window().setPosition(new Point(0, 0));
41 | driver.manage().window().setSize(new Dimension(1024, 768));
42 |
43 | // Enable native JS command
44 | JavascriptExecutor jse = (JavascriptExecutor) driver;
45 |
46 | // Test on target site
47 | driver.get(baseURL + '/');
48 | jse.executeScript("$('#sample-modal').modal('hide');");
49 | jse.executeScript("window.scrollTo(0,document.body.scrollHeight);");
50 | driver.findElement(By.cssSelector('#login')).click();
51 | driver.findElement(By.cssSelector('#search')).sendKeys('sample keyword');
52 | driver.findElement(By.xpath("(//button[@type='submit'])[0]")).click();
53 | driver.quit();
54 | }
55 | }
56 | ~~~~
57 |
58 |
59 | #### Run Selenium grid
60 |
61 | - Open terminal
62 | - Move to directory which have `Selenium Standalone Server` file
63 | - `java -jar selenium-server-standalone-2.xx.0.jar -role hub`
64 | - Check URL `localhost:4444/grid/console/` on browser
65 | - Open another terminal
66 | - `java -jar selenium-server-standalone-2.xx.0.jar -role webdriver http://127.0.0.1:4444/grid/register -port 5566`
67 | - Check URL `localhost:4444/grid/console/` on browser
68 | - Open `SeleniumTest.java` and run this code
69 | - Check URL `localhost:5566/wd/hub/` on browser *(Sessions)*
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Web stack architecture
2 |
3 |
4 |
5 | # Contents in this repository
6 |
7 | ## Ubuntu basic settings
8 |
9 | - Install basic packages
10 | - Set timezone
11 | - Customize **vim** editor
12 | - Install **zshell** and oh-my-zshell
13 | - Install **Fail2ban** to protect from malicious attack
14 | - Configure **git** setting
15 | - Install **nginx** *(Recommend version upper than 1.6)*
16 | - Install **MySQL**
17 | - Install **PostgreSQL**
18 |
19 | #### Mac OS X basic settings
20 | - Customize **terminal profile**
21 | - Optimize key input
22 | - Install **brew**
23 |
24 |
25 | ## Django basic settings
26 |
27 | - Install django and helpful packages
28 | - Clone sample django project if exist
29 | - Connect with **MySQL**
30 | - Connect with **PostgreSQL**
31 | - When **schema changed**
32 | - Use **django-suit** *(Custom admin interface)*
33 | - Use **django-compressor** *(Compress static files)*
34 | - Install **redis** and connect with django
35 | - Use **redisboard** at admin
36 | - Redis command
37 | - Install **celery** and connect with django
38 | - Celery command
39 | - Use **cerely beat** as cron task runner
40 | - Celery beat command
41 | - Install uWSGI and configure **Nginx and uWSGI settings**
42 | - Nginx command
43 | - uWSGI command
44 | - When number of **CPU** core or **memory** size changed
45 | - Configure **New Relic** settings
46 | - Install **Pillow** for image processing
47 |
48 |
49 | ## Django code snippets
50 |
51 | - **Internationalization** *(Localization)*
52 | - Send **mail** with template
53 | - Use **redis** to manage in-memory DB
54 | - Use **celery** to run task asynchronously
55 | - Use **pillow** to process image
56 | - Upload image to **cloudinary**
57 | - Detect **facebook** deauthorization
58 | - Use **firebase** as realtime DB
59 |
60 |
61 | ## Deploy django with Amazon Web Services
62 |
63 | - **EC2** *(OS: ubuntu 14.04 LTS)*
64 | - Use fixed IP with **Elastic IPs**
65 | - Load balance with **ELB**(Elastic Load Balancer)
66 | - Adapt SSL ceritificate at **ELB**
67 | - **Auto Scaling Groups** with **Cloud Watch**
68 | - Get access permission with **IAM**(Identity & Access Management)
69 | - **Route** 53 *(DNS)*
70 | - **RDS** *(MySQL)*
71 | - **ElastiCache** *(Redis)*
72 | - **S3** *(Storage)*
73 | - **CloudFront** *(CDN)*
74 |
75 |
76 | ## Utilities wiki and snippets
77 |
78 | - Deploy with **Fabric**
79 | - Manage package with **npm**
80 | - Use **Webpack** as module bundler
81 | - Use **Gulp** as task runner
82 | - Use **SASS** for stylesheet
83 | - Multi browser test by **Selenium grid**
84 | - Use **Docker** at Mac OS X
85 | - **MeteorJS** wiki
86 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/meteor-wiki.md:
--------------------------------------------------------------------------------
1 | #### Install Meteor framework and MongoDB at once
2 |
3 | ~~~~
4 | $ curl https://install.meteor.com/ | sh
5 | ~~~~
6 |
7 |
8 | #### Create and build Meteor project
9 |
10 | ~~~~
11 | $ meteor create {PROJECT NAME}
12 | $ meteor run
13 | ~~~~
14 |
15 |
16 | #### Check basic CRUD methods
17 |
18 | - Run MongoDB console
19 |
20 | ~~~~
21 | $ meteor mongo
22 | ~~~~
23 |
24 | - MongoDB native command
25 |
26 | ~~~~
27 | # Create
28 | mongo > db.tableName.insert(
29 | {fieldA: 1, fieldB: 'foo'}
30 | );
31 |
32 | # Read
33 | mongo > db.tableName.find(
34 | {fieldA: 1},
35 | {fieldA: 1, fieldB: 1}
36 | );
37 |
38 | # Update
39 | mongo > db.tableName.update(
40 | {fieldA: 1},
41 | {$set: {fieldB: 'foo changed'}},
42 | {multi: true}
43 | );
44 |
45 | # Delete
46 | mongo > db.tableName.remove(
47 | {fieldA: 1}
48 | );
49 | ~~~~
50 |
51 | - Meteor's Collection API
52 |
53 | ~~~~
54 | # Declare Meteor collection
55 | TableName = new Meteor.Collection('tableName');
56 |
57 | # Create
58 | TableName.insert(
59 | {fieldA: 1, fieldB: 'foo'}
60 | );
61 |
62 | # Read
63 | TableName.find(
64 | {fieldA: 1},
65 | {fields: {fieldA: 1, fieldB: 1}}
66 | );
67 |
68 | # Update
69 | TableName.update(
70 | {fieldA: 1},
71 | {$set: {fieldB: 'foo changed'}},
72 | {multi: true}
73 | );
74 |
75 | # Delete
76 | TableName.remove(
77 | {fieldA: 1}
78 | );
79 | ~~~~
80 |
81 |
82 | #### Install packages (Find more at atmosperejs.com)
83 |
84 | ~~~~
85 | $ meteor add {PACKAGE NAME}
86 | ~~~~
87 |
88 |
89 | #### Some helpful packages
90 |
91 | - accounts-password *(User account system)*
92 | - iron:router *(Router)*
93 | - aldeed:collection2 *(Automatic validation of insert and update)*
94 | - email *(Send email)*
95 | - twbs:bootstrap *(Bootstrap 3)*
96 | - rajit:bootstrap3-datepicker *(Bootstrap 3 datepicker)*
97 | - nemo64:bootstrap *(Configuration for Bootstrap 3)*
98 | - fourseven:scss *(SASS)*
99 | - meteorhacks:fast-render *(Render app before DDP connection alive)*
100 | - force-ssl *(Force to use SSL)*
101 |
102 |
103 | #### Remove some insecure packages
104 |
105 | ~~~~
106 | $ meteor remove autopublish insecure
107 | ~~~~
108 |
109 |
110 | #### Check installed package list
111 |
112 | ~~~~
113 | $ meteor list
114 | ~~~~
115 |
116 |
117 | #### Set directory structure
118 |
119 | - **client** *(Front-end source code like HTML, JS, CSS)*
120 | - **lib** *(Common code for both client and server)*
121 | - **private** *(Resources only accessible from the server side)*
122 | - **public** *(Accessible with root path ('/'). e.g. favicon.ico)*
123 | - **server** *(Back-end source code)*
124 |
--------------------------------------------------------------------------------
/5.utilities-wiki-and-snippets/deploy-with-fabric.md:
--------------------------------------------------------------------------------
1 | #### Install `fabric`
2 |
3 | ~~~~
4 | $ pip install fabric
5 | $ cd {PROJECT ROOT PATH}
6 | $ vi fabfile.py
7 | ~~~~
8 |
9 |
10 | #### Basic of `fabfile.py`
11 |
12 | ~~~~
13 | #!/bin/bash
14 | import os
15 | from fabric.api import *
16 |
17 | ROOT_DIR = os.path.dirname(__file__)
18 | PROJECT_NAME = {PROJECT NAME}
19 |
20 | # Deploy server information
21 | env.hosts = {HOST IP}
22 | env.user = 'ubuntu'
23 | env.key_filename = {PEM FILE PATH}
24 | env.port = 22
25 |
26 |
27 | def deploy():
28 | """
29 | Deploy at remote server
30 | """
31 | with cd(ROOT_DIR):
32 | sudo("git pull origin master")
33 | sudo("ps -ef | grep uwsgi | grep -v grep | awk '{print $2}' | xargs kill -15")
34 | sudo("uwsgi --uid www-data --gid www-data --emperor /etc/uwsgi/vassals --master --die-on-term --daemonize=" + ROOT_DIR + "/logs/uwsgi.log")
35 | ~~~~
36 |
37 |
38 | #### Install `boto` to integrate with Amazon Web Services
39 |
40 | ~~~~
41 | $ pip install boto3
42 | ~~~~
43 |
44 | - Edit `fabfile.py`
45 |
46 | ~~~~
47 | #!/bin/bash
48 | import os
49 | from boto3.session import Session
50 | from fabric.api import *
51 |
52 | ROOT_DIR = os.path.dirname(__file__)
53 | PROJECT_NAME = {PROJECT NAME}
54 |
55 | AWS_ACCESS_KEY_ID = {AWS ACCESS KEY ID}
56 | AWS_SECRET_ACCESS_KEY = {AWS SECRET ACCESS KEY}
57 |
58 |
59 | # Deploy server information
60 | env.hosts = []
61 | env.user = 'ubuntu'
62 | env.key_filename = {PEM FILE PATH}
63 | env.port = 22
64 |
65 | session = Session(aws_access_key_id=AWS_ACCESS_KEY_ID,
66 | aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
67 | region_name='ap-northeast-2') # SEOUL REGION
68 |
69 | ec2 = session.resource('ec2')
70 |
71 | for instance in ec2.instances.all():
72 | env.hosts.append(instance.public_dns_name)
73 |
74 |
75 | def deploy():
76 | """
77 | Deploy at remote server
78 | """
79 | with cd(ROOT_DIR):
80 | sudo("git pull origin master")
81 | sudo("ps -ef | grep uwsgi | grep -v grep | awk '{print $2}' | xargs kill -15")
82 | sudo("uwsgi --uid www-data --gid www-data --emperor /etc/uwsgi/vassals --master --die-on-term --daemonize=" + ROOT_DIR + "/logs/uwsgi.log")
83 | ~~~~
84 |
85 |
86 | #### Separate local command with remote command
87 |
88 | ~~~~
89 | from fabric.operations import local as lrun, run
90 | from fabric.api import task
91 | from fabric.state import env
92 |
93 | @task
94 | def localhost():
95 | env.run = lrun
96 | env.hosts = ['localhost']
97 |
98 | @task
99 | def remote():
100 | env.run = run
101 | env.hosts = ['some.remote.host']
102 |
103 | @task
104 | def install():
105 | env.run('deployment command')
106 | ~~~~
107 |
108 | - Install on localhost : `fab localhost install`
109 | - Install on remote : `fab remote install`
110 |
111 |
--------------------------------------------------------------------------------
/3.django-code-snippets/detect-facebook-deauthorization.md:
--------------------------------------------------------------------------------
1 | #### Pre-settings at facebook developers page
2 |
3 | - Facebook Developers > `My Apps` > `Settings` > `Advanced`
4 | - Put `Deauthorize Callback URL` (e.g. `https://mysite.com/facebook/deauthorize/`)
5 |
6 |
7 | #### `urls.py`
8 |
9 | ~~~~
10 | urlpatterns += patterns(
11 | url(
12 | regex=r'^facebook/deauthorize/$',
13 | view='deautorize_facebook_logged_in_user'
14 | ),
15 | )
16 | ~~~~
17 |
18 |
19 | #### `settings.py`
20 |
21 | ~~~~
22 | FACEBOOK_SECRET_CODE = {FACEBOOK SECRET CODE}
23 | ~~~~
24 |
25 |
26 | #### `utilities.py`
27 |
28 | ~~~~
29 | import base64
30 | import hashlib
31 | import hmac
32 | import json
33 |
34 | FACEBOOK_SECRET_CODE = getattr(settings, 'FACEBOOK_SECRET_CODE')
35 |
36 |
37 | def base64_url_decode(raw_url):
38 | """
39 | Decode URL by base64
40 | """
41 | padding_factor = (4 - len(raw_url) % 4) % 4
42 | raw_url += "="*padding_factor
43 |
44 | return base64.b64decode(unicode(raw_url).translate(dict(zip(map(ord, u'-_'), u'+/'))))
45 |
46 |
47 | def parse_facebook_signed_request(signed_request):
48 | """
49 | Parse facebook signed request and recognize user ID
50 | """
51 | temp = signed_request.split('.', 2)
52 | encoded_sig = temp[0]
53 | payload = temp[1]
54 |
55 | sig = base64_url_decode(encoded_sig)
56 | data = json.loads(base64_url_decode(payload))
57 |
58 | # Unknown algorithm
59 | if data.get('algorithm').upper() != 'HMAC-SHA256':
60 | return None
61 | else:
62 | expected_sig = hmac.new(FACEBOOK_SECRET_CODE, msg=payload, digestmod=hashlib.sha256).digest()
63 |
64 | if sig != expected_sig:
65 | return None
66 | else:
67 | return data
68 | ~~~~
69 |
70 |
71 | #### `views.py`
72 |
73 | ~~~~
74 | from django.views.decorators.csrf import csrf_exempt
75 | from django.http import JsonResponse
76 | from django.views.decorators.http import require_http_methods
77 | from utilities import parse_facebook_signed_request
78 |
79 | @csrf_exempt
80 | @require_http_methods(['POST'])
81 | def deauthorize_facebook_logged_in_user(request):
82 | """
83 | Deauthorize facebook logged in user
84 | """
85 | if not 'signed_request' in request.POST:
86 | return JsonResponse({
87 | 'state': 'fail',
88 | 'code': 1,
89 | 'message': 'Signed request parameter is required.'
90 | })
91 |
92 | data = parse_facebook_signed_request(request.POST['signed_request'])
93 |
94 | if data is None:
95 | return JsonResponse({
96 | 'state': 'fail',
97 | 'code': 2,
98 | 'message': 'Invalid signed request.'
99 | })
100 |
101 | facebook_user_id = data['user_id']
102 |
103 | return JsonResponse({
104 | 'state': 'success',
105 | 'code': 1,
106 | 'message': 'Succeed to get deauthorized facebook user ID.'
107 | })
108 | ~~~~
109 |
--------------------------------------------------------------------------------
/1.ubuntu-basic-settings/.vimrc:
--------------------------------------------------------------------------------
1 | " Pre-requirements
2 | " $ sudo apt-get install vim ctags cmake python-dev
3 | " Install Vundle
4 | " $ mkdir -p ~/.vim/bundle/
5 | " $ cd ~/.vim/bundle/
6 | " $ git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim
7 | " Install Plugins
8 | " $ vim [:PluginInstall]
9 | " Compile YouCompleteMe
10 | " $ cd ~/.vim/bundle/YouCompleteMe
11 | " $ ./install.sh
12 | set nocompatible
13 | filetype off
14 | set rtp+=~/.vim/bundle/Vundle.vim
15 | call vundle#begin()
16 | Plugin 'gmarik/Vundle.vim' " Manage Vundle Package
17 | Plugin 'Valloric/YouCompleteMe' " Auto complete
18 | Plugin 'majutsushi/tagbar' " Check function and global variable at side bar
19 | Plugin 'scrooloose/nerdtree' " Show directory tree at side bar
20 | Plugin 'scrooloose/syntastic' " Check Syntax error when save (includes PEP)
21 | Plugin 'scrooloose/nerdcommenter' " Annotate block (\cc) or delete block (\cu)
22 | Plugin 'nathanaelkane/vim-indent-guides' " Indent Guides
23 | Plugin 'altercation/vim-colors-solarized' " Color scheme
24 | Plugin 'bling/vim-airline' " Status bar
25 | Plugin 'kien/ctrlp.vim' " File finder and manage buffers
26 | call vundle#end()
27 | filetype plugin indent on
28 |
29 | " Use solarized color scheme
30 | syntax enable
31 | set background=dark
32 | if !has('gui_running')
33 | let g:solarized_termtrans=1 " Compatibility for Terminal
34 | if !(&t_Co >= 256 || $TERM == 'xterm-256color')
35 | set t_Co=16
36 | let g:solarized_termcolors=16 " Make Solarized use 16 colors for Terminal support
37 | endif
38 | endif
39 | colorscheme solarized
40 |
41 | " Indent Guides
42 | let g:indent_guides_enable_on_vim_startup=1
43 | let g:indent_guides_start_level=2
44 | let g:indent_guides_auto_colors=0
45 | autocmd VimEnter,Colorscheme * :hi IndentGuidesEven ctermbg=0
46 |
47 | " Default settings
48 | set autoindent " Auto indentation
49 | set smartindent " Smart indentation
50 | set tabstop=2
51 | set shiftwidth=2
52 | set softtabstop=2
53 | set hlsearch " Highlight search keywords
54 | set encoding=utf-8 " Encoding
55 | set fileencodings=utf-8,euckr
56 | set laststatus=2 " Show status bar always
57 | set splitright " Position vertically split window to right
58 | set backspace=indent,eol,start " allow backspacing over everything in insert mode
59 |
60 | " Filetype customization
61 | autocmd Filetype html setlocal tabstop=2 shiftwidth=2 expandtab
62 | autocmd Filetype ruby setlocal tabstop=2 shiftwidth=2 expandtab
63 | autocmd Filetype javascript setlocal tabstop=2 shiftwidth=2 softtabstop=0 expandtab
64 | autocmd Filetype python setlocal tabstop=8 shiftwidth=4 softtabstop=4 expandtab
65 |
66 | " CtrlP ignoring list
67 | let g:ctrlp_custom_ignore = {
68 | \ 'dir': '\v[\/](\.git|node_modules|\.sass-cache|bower_components|build|_site)$',
69 | \ 'file': '\v\.(exe|so|dll)$'}
70 |
71 | " Memorize cursor position
72 | au BufReadPost *
73 | \ if line("'\"") > 0 && line("'\"") <= line("$") |
74 | \ exe "norm g`\"" |
75 | \ endif
76 |
77 | " Vim Key Mapping
78 | nmap :tabprev
79 | nmap :tabnext
80 | nmap gg=G
81 | nmap :wq
82 | nmap :!reset
83 | nmap :TagbarToggle
84 | nmap :set paste!
85 | nmap :set paste
86 | nmap :CtrlP
87 | nmap :NERDTree
88 |
--------------------------------------------------------------------------------
/2.django-basic-settings/nginx.conf:
--------------------------------------------------------------------------------
1 | user www-data;
2 | pid /run/nginx.pid;
3 |
4 | # Worker Settings (Maximum workers = worker_processes * worker_connections)
5 | worker_processes auto; # Usually number of CPU cores
6 |
7 | events {
8 | worker_connections 1024; # Usually memory size in Megabytes
9 | multi_accept on; # Needs enough number of workers
10 | use epoll; # Requires linux kernel version upper than 2.6
11 | }
12 |
13 | http {
14 | sendfile on; # Copy data between one FD and other from within the kernel
15 | tcp_nopush on; # Send its HTTP response head in one packet
16 | tcp_nodelay on; # Disable buffer data-sends (Good for sending frequent small bursts of data in real time)
17 | types_hash_max_size 2048; # Increase this value if types_hash error occurs
18 |
19 | include /etc/nginx/mime.types;
20 | default_type application/octet-stream;
21 |
22 | # Timeout Settings
23 | keepalive_timeout 15;
24 | client_body_timeout 10; # Send "request timed out" message to client if the body is not loaded in time
25 | client_header_timeout 10; # Send "request timed out" message to client if the body is not loaded in time
26 | send_timeout 10; # Delete client connection if the client stops reading data (Higher value, higher memory usage)
27 |
28 | # Logging Settings
29 | access_log /var/log/nginx/access.log;
30 | error_log /var/log/nginx/error.log;
31 |
32 | # Gzip Settings
33 | gzip on; # Enable compression
34 | gzip_disable "msie6"; # Prevent bug from IE 6
35 | gzip_vary on; # Return "Vary: Accept-Encoding" on header
36 | gzip_comp_level 6; # Higher value, more compression
37 | gzip_proxied expired no-cache no-store private auth; # Cases of gzip compression when request come through proxy
38 | gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
39 |
40 | # Virtual Host Configs
41 | include /etc/nginx/conf.d/*.conf;
42 | include /etc/nginx/sites-enabled/*;
43 |
44 | # DOS Attack Protection
45 | limit_req_zone $binary_remote_addr zone=req_limit_per_ip:100m rate=20r/s; # Do not allow upper than 20 requests per second at an average
46 | limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:100m;
47 |
48 | # Connect to File Socket
49 | upstream {PROJECT NAME} {
50 | server unix:/dev/shm/{PROJECT NAME}.sock;
51 | }
52 |
53 | server {
54 | listen 80;
55 | server_name {DOMAIN OR PUBLIC IP}; # Place '_' for the development server
56 | charset utf-8;
57 | client_max_body_size 20M;
58 |
59 | # etags attribute requires version upper than 1.3 (default: on)
60 |
61 | # Logging Settings (Disable access log to boost up the speed)
62 | access_log {PROJECT PATH}/logs/nginx.access.log;
63 | error_log {PROJECT PATH}/logs/nginx.error.log;
64 |
65 | # Django static (Cache-control on HTTP header on client's browser)
66 | location /static {
67 | alias {PROJECT PATH}/static;
68 | expires 30d;
69 | }
70 |
71 | # Non-media requests to the Django server
72 | location / {
73 | # DOS Attack Protection
74 | limit_req zone=req_limit_per_ip burst=20 nodelay; # Bursts not exceeding 20 requests per second
75 | limit_conn conn_limit_per_ip 100; # Maximum 100 connections per IP
76 |
77 | uwsgi_pass {PROJECT NAME};
78 | include /etc/nginx/uwsgi_params;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/1.ubuntu-basic-settings/README.md:
--------------------------------------------------------------------------------
1 | # Ubuntu basing settings
2 |
3 | #### Install basic packages
4 |
5 | ~~~~
6 | $ apt-get update
7 | $ apt-get install build-essential git python-dev libxml2-dev libxslt1-dev libssl-dev libffi-dev libcurl4-openssl-dev python-pip curl sudo wget htop
8 | $ pip install --upgrade pip
9 | ~~~~
10 |
11 |
12 | #### Set timezone
13 |
14 | ~~~~
15 | $ dpkg-reconfigure tzdata [Select city]
16 | ~~~~
17 |
18 |
19 | #### Customize vim editor
20 |
21 | ~~~~
22 | $ sudo apt-get install vim ctags cmake
23 | $ vi ~/.vimrc
24 | ~~~~
25 |
26 | - Copy and paste `.vimrc`
27 |
28 | ~~~~
29 | $ mkdir -p ~/.vim/bundle
30 | $ cd ~/.vim/bundle
31 | $ git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim
32 | $ vi [Ignore errors][:PluginInstall]
33 | $ cd ~/.vim/bundle/YouCompleteMe
34 | $ ./install.py
35 | ~~~~
36 |
37 |
38 | #### Install zshell and oh-my-zshell
39 |
40 | ~~~~
41 | $ sudo apt-get install zsh
42 | $ chsh -s `which zsh`
43 | ~~~~
44 |
45 | - Restart server
46 | - Check default shell (`echo $SHELL`)
47 |
48 | ~~~~
49 | $ curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh
50 | $ /bin/zsh
51 | ~~~~
52 |
53 | - Append following codes
54 |
55 | ~~~~
56 | $ vi ~/.zshrc
57 |
58 | setopt PROMPT_SUBST
59 | PROMPT='%(!.%F{red}.%F{cyan})%n%f@%F{yellow}%m%f%(!.%F{red}.)%} ➜ %{$(pwd|grep --color=always /)%${#PWD}G%} %{$fg_bold[blue]%}$(git_prompt_info)%{$fg_bold[blue]%} % %{$reset_color%}'
60 |
61 | $ source ~/.zshrc
62 | ~~~~
63 |
64 |
65 | #### Install Fail2ban to protect from malicious attack
66 |
67 | ~~~~
68 | $ sudo apt-get install fail2ban
69 | $ cd /etc/fail2ban
70 | $ cp jail.conf jail.local
71 | $ vi jail.local
72 |
73 | [DEFAULT]
74 | ignoreip = {SAFE IP}
75 |
76 | [ssh]
77 | enabled = true
78 |
79 | [ssh-ddos]
80 | enabled = true
81 | destemail = {EMAIL ADDRESS}
82 |
83 | $ sudo service fail2ban restart
84 | ~~~~
85 |
86 |
87 | #### Configure git setting
88 |
89 | ~~~~
90 | $ git config --global user.name {USERNAME}
91 | $ git config --global user.email {EMAIL ADDRESS}
92 | $ git config --global core.editor "vim"
93 | ~~~~
94 |
95 |
96 | #### Install nginx *(Recommend version upper than 1.6)*
97 |
98 | - Only for ubuntu <= 14.04
99 |
100 | ~~~~
101 | $ sudo apt-get install software-properties-common
102 | $ sudo add-apt-repository ppa:nginx/stable [Enter]
103 | ~~~~
104 |
105 | - Then,
106 |
107 | ~~~~
108 | $ sudo apt-get update
109 | $ sudo apt-get install nginx
110 | $ nginx -v [Check version]
111 | $ sudo service nginx start
112 | ~~~~
113 |
114 | - Check URL `{PUBLIC IP}:80` on browser
115 |
116 |
117 | #### Install MySQL
118 |
119 | ~~~~
120 | $ sudo apt-get update
121 | $ sudo apt-get install mysql-server mysql-client libmysqlclient-dev [Enter root password]
122 | $ sudo service mysql start
123 | ~~~~
124 |
125 |
126 | #### Install PostgreSQL
127 |
128 | ~~~~
129 | $ sudo apt-get update
130 | $ sudo apt-get install libpq-dev build-dep python-psycopg2 postgresql postgresql-contrib [Enter password]
131 | $ sudo service postgresql start
132 | ~~~~
133 |
134 |
135 | # Mac OS X basic settings
136 |
137 | #### Customize terminal profile
138 |
139 | - Download solarized theme at here (e.g. `Solarized Dark.terminal`)
140 | - Open `Terminal` app
141 | - Open `Profile` by press key `Command` + `,`
142 | - `Profile` tab > Click gear icon > import > `Solarized Dark.terminal` > Click theme > Set default
143 |
144 |
145 | #### Optimize key input
146 |
147 | - Open `terminal`
148 |
149 | ~~~~
150 | # Enable key repeat
151 | $ defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
152 | ~~~~
153 |
154 | - Download Karabiner from here
155 | - `Change Key` > `For PC Users`
156 | - Check `Use PC Style Home/End` and `Use PC Style PageUp/PageDown`
157 |
158 |
159 | #### Install brew
160 |
161 | - Open `terminal`
162 |
163 | ~~~~
164 | $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
165 | ~~~~
166 |
167 | - Put password
168 | - Install some requirements
169 |
170 | - Install use useful libraries
171 |
172 | ~~~~
173 | $ brew install python cmake zsh vim
174 | $ vi {Shell Configuration file}
175 |
176 | alias vi='/usr/local/bin/vim'
177 | alias vim='/usr/local/bin/vim'
178 | ~~~~
179 |
180 |
181 | #### Install X-code command line developers tool
182 |
183 | ~~~~
184 | $ xcode-select --install
185 | ~~~~
186 |
--------------------------------------------------------------------------------
/4.deploy-django-with-aws/README.md:
--------------------------------------------------------------------------------
1 | # Deploy django with Amazon Web Services
2 |
3 | - **EC2** *(OS: ubuntu 14.04 LTS)*
4 | - Use fixed IP with **Elastic IPs**
5 | - Load balance with **ELB**(Elastic Load Balancer)
6 | - Adapt SSL ceritificate at **ELB**
7 | - **Auto Scaling Groups** with **Cloud Watch**
8 | - Get access permission with **IAM**(Identity & Access Management)
9 | - **Route** 53 *(DNS)*
10 | - **RDS** *(MySQL)*
11 | - **ElastiCache** *(Redis)*
12 | - **S3** *(Storage)*
13 | - **CloudFront** *(CDN)*
14 |
15 |
16 | ## EC2
17 |
18 | - `EC2 menu` > `Launch Instance` > `Ubuntu Server 14.04 LTS`
19 | - Click `Next` until `6. Configure Security Group`
20 |
21 | > _If the application is CPU intensive, C level instance is more suitable than T level instance_
22 |
23 | - Set inbound rule for security group as following
24 |
25 | Type | Protocol | Port | Source
26 | -----|----------|------|-------
27 | SSH | TCP | 22 | 0.0.0.0/0 (or Your IP)
28 | HTTP | TCP | 80 | 0.0.0.0/0 (for nginx)
29 | HTTPS | TCP | 443 | 0.0.0.0/0 (for nginx)
30 | Custom TCP Rule | TCP | 8000 | 0.0.0.0/0 (for test)
31 |
32 | - `Review and Launch` > `Launch`
33 | - Create PEM file and save it into local directory *(DO NOT share or delete PEM file)*-
34 |
35 | ~~~~
36 | $ chmod 400 {PATH TO PEM FILE}
37 | ~~~~
38 |
39 |
40 | #### Use fixed IP with Elastic IPs
41 |
42 | - `EC2 menu` > `Elastic IPs` > `Allocate New Address` > `Yes, Allocate`
43 | - Right click IP > `Release addresses` > `Yes, Release` > Select instance > `Release`
44 | - From now on, you can make SSH connect to instance with PEM file
45 |
46 | ~~~~
47 | $ ssh -i {PATH TO PEM FILE} ubuntu@{EC2 PUBLIC DNS}
48 |
49 | OR,
50 |
51 | $
52 | $ vi ~/.ssh/config
53 |
54 | Host *
55 | UseKeychain yes
56 | AddKeysToAgent yes
57 | TCPKeepAlive yes
58 | ServerAliveInterval 120
59 |
60 | host {NICKNAME}
61 | Hostname {EC2 PUBLIC DNS}
62 | User ubuntu
63 | IdentityFile {PATH TO PEM FILE}
64 |
65 | $ ssh-add {PEM FILE}
66 | $ ssh {NICKNAME}
67 | ~~~~
68 |
69 | #### Load balance with ELB(Elastic Load Balancer)
70 |
71 | - Issue SSL certificate through *Certificate Manager*
72 | - `EC2 menu` > `Load Balancers` > `Create Load Balancer` > `Classic Load Balancer`
73 | - Put `Load Balancer name` > Click `Add` > Choose `HTTPS` > Click `Next`
74 | - Assign security group same as EC2 > Click `Next`
75 | - Choose exsiting certificate that we made before
76 | - Set `Ping Path` value `/health_check` for Health checks > Click `Next`
77 | - Choose EC2 instance
78 | - Edit `nginx.conf`
79 |
80 | ~~~~
81 | http {
82 |
83 | server {
84 |
85 | listen 80;
86 |
87 | location /health_check {
88 | access_log off;
89 | return 200;
90 | }
91 |
92 | location / {
93 |
94 | if ($http_x_forwarded_proto != 'https') {
95 | return 301 https://$host$request_uri;
96 | }
97 | }
98 | }
99 |
100 | server {
101 |
102 | listen 443;
103 |
104 | location /health_check {
105 | access_log off;
106 | return 200;
107 | }
108 |
109 | location / {
110 | {COPY AND PASTE EXISTING CODE IN UPPER BLOCK WITH 80 PORT}
111 | }
112 | }
113 | }
114 | ~~~~
115 |
116 | - Go to Route53 > Edit record set > Type : A record > Alias target : ELB that we made right before
117 |
118 | #### Adapt SSL certificate at ELB (Deprecated)
119 |
120 | - Recommend to use *AWS Certificate Manager* instead of following steps
121 | - Create private key
122 |
123 | ~~~~~
124 | $ openssl req -new -newkey rsa:2048 -nodes -keyout mysite_com.key -out mysite_com.csr
125 | ~~~~~
126 |
127 | - Purchase Comodo positive SSL certificate and put mysite_com.key to activate SSL
128 | - Check email from Comodo which contains below files
129 | - Root CA Certificate - `AddTrustExternalCARoot.crt`
130 | - Intermediate CA Certificate - `COMODORSAAddTrustCA.crt`
131 | - Intermediate CA Certificate - `COMODORSADomainValidationSecureServerCA.crt`
132 | - PositiveSSL Certificate - `mysite_com.crt`
133 | - Merge above files into one *(Be careful of the order)*
134 |
135 | ~~~~
136 | $ cat mysite_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > mysite_com_bundle.crt
137 | ~~~~
138 |
139 | - `EC2 menu` > `Load Balancers`
140 | - Select load balancer and click `Listeners` tab
141 | - Click `Edit` and add listener as following
142 |
143 | Load Balancer Protocol | Load Balancer Port | Instance Protocol | Instance Port | Cipher | SSL Certificate
144 | -----------------------|--------------------|-------------------|---------------|--------|----------------
145 | HTTPS | 443 | HTTP | 80 | Use default | Add
146 |
147 | - Click `Change` on `SSL Certificate` column and add certificate
148 | - Private key : `mysite_com.key`
149 | - Public key : `mysite_com_bundle.crt`
150 | - Certificate chain : `None`
151 | - Edit `nginx.conf` to redirect `HTTP` to `HTTPS`
152 |
153 | ~~~~
154 | server {
155 | listen 80;
156 | ...
157 | location / {
158 | if ($http_x_forwarded_proto != 'https') {
159 | return 301 https://$host$request_uri;
160 | }
161 | ...
162 | }
163 | }
164 | ~~~~
165 |
166 | #### Auto Scaling Groups with Cloud Watch
167 |
168 | - `EC2 menu` > `Instances`
169 | - Right click instance > `Image` > `Create Image` > Put `Image name` > `Create Image`
170 | - `EC2 menu` > `Launch Configurations` > `Create launch configuration`
171 | - `My AMIs` > Select AMI > Select instance type > Put `Name` > Check `Monitoring` > Click `Advanced Details`
172 | - Fill out `User data` as initial script when instance created. For example,
173 |
174 | ~~~~
175 | #!/bin/bash
176 | cd {PROJECT PATH}
177 | git pull origin master (OR git clone {REMOTE URL} if pull request requires username and password)
178 | npm install
179 | cd {PATH TO PIP REQUIRMENTS FILE}
180 | pip install -r requirements.txt
181 | cd {PROJECT PATH}
182 | sudo service nginx restart
183 | fab update_staticfiles
184 | fab run_uwsgi
185 | fab run_celery
186 | ~~~~
187 |
188 | - `Next: Add Storage` > `Next: Configure Security Group`
189 | - `Select an existing security group` > Select same one with EC2 > `Review` > `Create launch configuration`
190 | - `Choose an existing key pair` > Select same one with EC2 > `Create launch configuration`
191 | - Put `Group name` > Click empty input of `Subnet` > Select all *(...northeast...)*
192 | - Click `Advanced Details` > Check `Load Balancing` > Click empty input of `Load Balancing` > Choose ELB
193 | - Check `Monitoring` > `Next: Configure scaling pollicies`
194 | - Select `Use scaling policies to adjust the capacity of this group` > Put minimum and maximum number of instances. For example,
195 | - Scale between `1` and `4` instances.
196 | - Fill out `Increase Group Size`
197 | - `Take the action` : `Add` `1` `instances`
198 | - `Add new alarm` > Uncheck `Send a notification to` > Whenever `Average` of `CPU Utilization` Is `>=` `80` Percent For at least `1` consecutive period(s) of `1 Minute` > `Create alarm`
199 | - Fill out `Decrease Group Size`
200 | - `Take the action` : `Remove` `1` `instances`
201 | - `Add new alarm` > Uncheck `Send a notification to` > Whenever `Average` of `CPU Utilization` Is `<=` `10` Percent For at least `1` consecutive period(s) of `1 Minute` > `Create alarm`
202 | - `Next: Configure Notifications` > `Add notification` > `create topic` > Put `topic name` and `email address`
203 | - `Review` > `Create Auto Scaling Group`
204 | - `EC2 menu` > `Instances`
205 | - Check new instance is initializing and terminate original instance
206 |
207 | #### Get access permission with IAM(Identity & Access Management)
208 |
209 | - `IAM` > `Users` > `Create New Users` > Put `User Name` > Click `Show User Security Credentials` > Check `Access Key ID` and `Secret Access Key` > `Close`
210 | - Click newly created user > `Permissions` > `Attach Policy` > Select `AmazonEC2FullAccess` > `Attach Policy`
211 | - Get "how to access AWS instances programmatically" at here
212 |
213 |
214 | ## Route 53
215 |
216 | - If you don't have domain yet, get domain from `Route 53 menu` > `Domain Registration`
217 | - `Route 53 menu` > `DNS Management` > `Create Hosted Zone`
218 | - Put `Domain Name`
219 | - Click `Create Record Set`
220 | - Put values as following
221 |
222 | Type | Alias | Alias Target or Value
223 | -----|-------|----------------------
224 | NS | No | {NAME SERVER LIST}
225 | A | Yes | {ELB A RECORD}
226 | MX | No | {MAIL SERVER}
227 |
228 |
229 | ## RDS
230 |
231 | - `RDS menu` > `Launch a DB Instance` > `MySQL`
232 | - Click `No` for `Multi-AZ deployment` option to use free-tier
233 | - Select `db.t2.micro` for `DB Instance Class` and `No` for `Multi-AZ Deployment`
234 |
235 | > _If the application mainly using ORM, high memory size would be required_
236 |
237 | - Put `DB Instance Identifier`, `Master Username`, `Master Password`
238 | - `Launch DB Instance`
239 | - Edit inbound rule of security group as following
240 |
241 | Type | Protocol | Port | Source
242 | -----|----------|------|-------
243 | MySQL | TCP | 3306 | 0.0.0.0/0
244 |
245 | - Create database with MySQL command
246 |
247 | ~~~~
248 | $ sudo su
249 | $ mysql -u {MASTER USERNAME} -p -h {RDS END POINT}
250 | $ {MASTER PASSWORD}
251 | mysql $ CREATE DATABASE {DB NAME} DEFAULT CHARACTER SET utf8;
252 | mysql $ exit;
253 | ~~~~
254 |
255 | - Edit `settings.py`
256 |
257 | ~~~~
258 | DATABASES = {
259 | 'default': {
260 | 'ENGINE': 'django.db.backends.mysql',
261 | 'NAME': '{DB NAME}',
262 | 'USER': '{MASTER USERNAME}',
263 | 'PASSWORD': '{MASTER PASSWORD}',
264 | 'HOST': '{RDS END POINT}',
265 | 'PORT': '3306',
266 | 'DEFAULT-CHARACTER-SET': 'utf8',
267 | }
268 | }
269 | ~~~~
270 |
271 | - Migrate database
272 |
273 | ~~~~
274 | $ cd {PROJECT PATH}
275 | $ ./manage.py migrate
276 | $ ./manage.py makemigrations {APPLICATION NAME}
277 | $ ./manage.py migrate {APPLICATION NAME}
278 | ~~~~
279 |
280 | - `RDS` > `Event Subscriptions` > `Create Event Subscription`
281 | - Put name and create topic > Select `source type` as `Instances` > Select instace > `Create`
282 |
283 |
284 | ## ElastiCache
285 |
286 | - `ElastiCache menu` > `Launch Cache Cluster` > `Redis`
287 | - Uncheck `Enable Replication` option to use free-tier
288 | - Put `Cluster Name` and select `cache.t2.micro` for `Node Type`
289 | - Create new security group as following inbound rule
290 |
291 | Type | Protocol | Port | Source
292 | -----|----------|------|-------
293 | Custom TCP Rule | TCP | 6379 | 0.0.0.0/0
294 |
295 | - Edit `settings.py`
296 |
297 | ~~~~
298 | CACHES = {
299 | 'default': {
300 | 'BACKEND': 'django_redis.cache.RedisCache',
301 | 'LOCATION': 'redis://{END POINT}:6379',
302 | 'OPTIONS': {
303 | 'CLIENT_CLASS': 'django_redis.client.DefaultClient',
304 | }
305 | }
306 | }
307 | ~~~~
308 |
309 |
310 | ## S3
311 |
312 | - `S3 menu` > `Create Bucket`
313 | - Put `Bucket Name` and `Create`
314 | - `Set properties` > `Set permissions` > `Next` > `Create`
315 | - Follow below steps ff you want to allow everyone to read files
316 | - `Permissions` > `Access Control List` > `Manage public permissions` > Everyone Group > Set `Read` for both `Object access` and `Permissions access`
317 | - `Permissions` > `Bucket Policy` > Copy and paste following snippet > `Save`
318 |
319 | ~~~~
320 | {
321 | "Version": "2008-10-17",
322 | "Id": "Policy1403276359730",
323 | "Statement": [
324 | {
325 | "Sid": "Stmt1403276358543",
326 | "Effect": "Allow",
327 | "Principal": {
328 | "AWS": "*"
329 | },
330 | "Action": "s3:GetObject",
331 | "Resource": "arn:aws:s3:::{BUCKET NAME}/*"
332 | }
333 | ]
334 | }
335 | ~~~~
336 |
337 |
338 | ## CloudFront
339 |
340 | - `CloudFront menu` > `Create distribution` > Choose `Web`
341 | - Click `Origin Domain Name` and choose `bucket` under `Amazon S3 Buckets`
342 | - `Create distribution`
343 | - You can get `sample.png` from `{CLOUDFRONT DOMAIN NAME}/{FOLDER NAME}/sample.png`
344 | - Note that `{BUCKET NAME}` is not included in URL
345 | - When you'd like to update cache, go to `invalidations` tab
346 |
--------------------------------------------------------------------------------
/2.django-basic-settings/README.md:
--------------------------------------------------------------------------------
1 | # Django basic settings
2 |
3 |
4 | #### Clone sample django project if exist
5 |
6 | ~~~~
7 | $ ssh-keygen
8 | $ cat ~/.ssh/id_rsa.pub
9 | ~~~~
10 |
11 | - Add public key to Github or Bitbucket
12 |
13 | ~~~~
14 | $ mkdir -p /var/www/
15 | $ cd /var/www/
16 | $ git clone {GIT REMOTE ORIGIN URL}
17 | ~~~~
18 |
19 | - If you want to remove existing packages,
20 |
21 | ~~~~
22 | $ pip freeze | xargs pip uninstall -y
23 | ~~~~
24 |
25 | - Install pip requirements
26 |
27 | ~~~~
28 | $ pip install -r {PATH TO PIP REQUIREMENTS}/requirements.txt
29 | ~~~~
30 |
31 |
32 | #### Install django
33 |
34 | ~~~~
35 | $ pip install django
36 | $ cd /var/www/
37 | $ django-admin startproject {PROJECT NAME}
38 | $ cd {PROJECT PATH}
39 | $ ./manage.py runserver 0.0.0.0:8000 [Ignore migration error messages]
40 | ~~~~
41 |
42 | - Check URL `{PUBLIC IP}:8000` on browser
43 |
44 |
45 | #### Connect with MySQL
46 |
47 | ~~~~
48 | $ pip install MySQL-python
49 | $ sudo service mysql restart
50 | $ mysql -u root -p [Enter password]
51 | mysql $ CREATE DATABASE {DB NAME} DEFAULT CHARACTER SET utf8;
52 | mysql $ exit;
53 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
54 |
55 | DATABASES = {
56 | 'default': {
57 | 'ENGINE': 'django.db.backends.mysql',
58 | 'NAME': '{DB NAME}',
59 | 'USER': 'root',
60 | 'PASSWORD': '{MySQL ROOT PASSWORD}',
61 | 'HOST': '',
62 | 'PORT': '',
63 | 'DEFAULT-CHARACTER-SET': 'utf8',
64 | },
65 | }
66 |
67 | $ cd {PROJECT PATH}
68 | $ ./manage.py migrate
69 | ~~~~
70 |
71 |
72 | #### Connect with PostgreSQL
73 |
74 | ~~~~
75 | $ pip install psycopg2
76 | $ sudo su - postgres
77 | postgresql $ createdb {DB NAME}
78 | postgresql $ createuser -P {USERNAME} [enter password]
79 | postgresql $ exit
80 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
81 |
82 | DATABASES = {
83 | 'default': {
84 | 'ENGINE': 'django.db.backends.postgresql_psycopg2',
85 | 'NAME': '{DB NAME}',
86 | 'USER': 'root',
87 | 'PASSWORD': '{PostgreSQL PASSWORD}',
88 | 'HOST': '127.0.0.1',
89 | 'PORT': '5432',
90 | }
91 | }
92 |
93 | $ cd {PROJECT PATH}
94 | $ ./manage.py migrate
95 | ~~~~
96 |
97 | - Note: If you using custom user model, it would be better to migrate after fill out your user model in `models.py`
98 |
99 |
100 | #### When schema changed
101 |
102 | ~~~~
103 | $ ./manage.py makemigrations {APP NAME}
104 | $ ./manage.py migrate {APP NAME}
105 | ~~~~
106 |
107 |
108 | #### Use django-suit *(Custom admin interface)*
109 |
110 | ~~~~
111 | $ pip install django-suit
112 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
113 |
114 | INSTALLED_APPS = (
115 | # django-suit should come before 'django.contrib.admin'
116 | 'suit',
117 | 'django.contrib.admin',
118 | ...
119 | )
120 |
121 | # Django < 1.9
122 | from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS
123 |
124 | TEMPLATE_CONTEXT_PROCESSORS += (
125 | 'django.core.context_processors.request',
126 | )
127 | ~~~~
128 |
129 | #### Install Django extensions
130 |
131 | ~~~~
132 | $ pip install django-extensions
133 | ~~~~
134 |
135 | - Commands
136 |
137 | ~~~~
138 | $ ./manage.py shell_plus
139 | ~~~~
140 |
141 |
142 | #### Use django-compressor *(Compress static files)*
143 |
144 | ~~~~
145 | $ pip install django-compressor
146 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
147 |
148 | INSTALLED_APPS += (
149 | 'compressor',
150 | )
151 |
152 | # Use compressor only for production mode
153 | COMPRESS_ENABLED = not DEBUG
154 | COMPRESS_URL = STATIC_URL
155 | COMPRESS_ROOT = STATIC_ROOT
156 | COMPRESS_OUTPUT_DIR = 'CACHE'
157 | STATICFILES_FINDERS += (
158 | 'compressor.finders.CompressorFinder',
159 | )
160 |
161 | $ vi {TEMPLATE FILE}
162 |
163 | {% load compress %}
164 | ...
165 | {% compress css %}
166 | ...
167 | {% endcompress %}
168 | ...
169 | {% compress js %}
170 | ...
171 | {% endcompress %}
172 |
173 | $ cd {PROJECT PATH}
174 | $ ./manage.py collectstatic --noinput
175 | ~~~~
176 |
177 |
178 | #### Install redis and connect with django
179 |
180 | ~~~~
181 | $ sudo apt-get install redis-server
182 | $ pip install redis django-redis
183 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
184 |
185 | CACHES = {
186 | 'default': {
187 | 'BACKEND': 'django_redis.cache.RedisCache',
188 | 'LOCATION': 'redis://127.0.0.1:6379/1',
189 | 'OPTIONS': {
190 | 'CLIENT_CLASS': 'django_redis.client.DefaultClient',
191 | }
192 | }
193 | }
194 | ~~~~
195 |
196 |
197 | #### Use redisboard at admin (Only works with local redis server)
198 |
199 | ~~~~
200 | $ pip install django-redisboard
201 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
202 |
203 | INSTALLED_APPS += (
204 | 'redisboard',
205 | )
206 |
207 | $ ./manage.py makemigrations redisboard
208 | $ ./manage.py migrate redisboard
209 | ~~~~
210 |
211 | - If you using django-compressor
212 |
213 | ~~~~
214 | $ ./manage.py collectstatic --noinput
215 | ~~~~
216 |
217 | - Go to admin page and login
218 | - `Redisboard` > `Redis Servers` > `Add Redis Server`
219 | - Label : `localhost` / Hostname : `127.0.0.1`
220 | - Check cache list at `Tools` > `Inspect`
221 |
222 |
223 | #### Redis command
224 |
225 | ~~~~
226 | $ service redis-server start # Run redis as daemon
227 | $ redis-cli save # Save redis
228 | $ redis-cli flushall # Flush redis DB
229 | $ redis-cli shutdown # Shutdown redis
230 | ~~~~
231 |
232 |
233 | #### Install uWSGI and configure Nginx and uWSGI settings
234 |
235 | ~~~~
236 | $ pip install uwsgi
237 | $ rm /etc/nginx/nginx.conf /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default
238 | $ vi {PROJECT PATH}/conf/nginx/nginx.conf
239 | ~~~~
240 |
241 | - Copy `nginx.conf` and customize `{{DOMAIN OR PUBLIC IP}}`, `{PROJECT NAME}` and `{PROJECT PATH}`
242 |
243 | ~~~~
244 | $ chmod 775 {PROJECT PATH}/conf/nginx/nginx.conf
245 | $ ln -s {PROJECT PATH}/conf/nginx/nginx.conf /etc/nginx/nginx.conf
246 | ~~~~
247 |
248 | - Copy `uwsgi.conf` and paste
249 |
250 | ~~~~
251 | $ chmod 775 {PROJECT PATH}/conf/uwsgi/uwsgi.conf
252 | $ ln -s {PROJECT PATH}/conf/uwsgi/uwsgi.conf /etc/init/uwsgi.conf
253 | $ vi {PROJECT PATH}/conf/uwsgi/{PROJECT NAME}.ini
254 | ~~~~
255 |
256 | - Copy `{PROJECT NAME}.ini` and customize `{PROJECT NAME}` and `{PROJECT PATH}`
257 |
258 | ~~~~
259 | $ chmod 775 {PROJECT NAME}.ini
260 | $ mkdir -p /etc/uwsgi/vassals/
261 | $ ln -s {PROJECT PATH}/conf/uwsgi/{PROJECT NAME}.ini /etc/uwsgi/vassals/
262 | ~~~~
263 |
264 | - Initiate log files
265 |
266 | ~~~~
267 | $ mkdir -p {PROJECT PATH}/logs/
268 | $ cd {PROJECT PATH}/logs/
269 | $ touch uwsgi.log uwsgi.pid
270 | $ chown www-data.www-data uwsgi.log uwsgi.pid
271 | ~~~~
272 |
273 |
274 | #### Nginx command
275 |
276 | ~~~~
277 | $ service nginx status # Check nginx status
278 | $ service nginx start # Start nginx
279 | $ service nginx restart # Restart nginx
280 | $ service nginx stop # Stop nginx
281 | ~~~~
282 |
283 |
284 | #### uWSGI command
285 |
286 | ~~~~
287 | $ uwsgi --uid www-data --gid www-data --emperor /etc/uwsgi/vassals --master --die-on-term --daemonize={LOG FILE PATH} # Run uWSGI
288 | $ ps -ef | grep uwsgi | grep -v grep | awk "{print $2}" | xargs kill -15' # Stop uWSGI
289 | ~~~~
290 |
291 |
292 | #### Install celery and connect with django
293 |
294 | - Note: We should install `django-celery 3.2.1` manually and integrate it with `celery 3.2.25`
295 |
296 | ~~~~
297 | $ pip install celery==3.2.25 amqp
298 | $ wget https://github.com/celery/django-celery/archive/v3.2.1.tar.gz
299 | $ tar xvfz v3.2.1.tar.gz
300 | $ cd django-celery-3.2.1
301 | $ python setup.py install
302 | ~~~~
303 |
304 | - Integrate celery with django
305 |
306 | ~~~~
307 | $ apt-get install rabbitmq-server
308 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
309 |
310 | import djcelery
311 |
312 | INSTALLED_APPS += (
313 | 'djcelery',
314 | )
315 |
316 | djcelery.setup_loader()
317 | BROKER_URL = 'amqp://guest:guest@localhost:5672/'
318 |
319 | $ vi {PROJECT PATH}/{PROJECT NAME}/wsgi.py
320 |
321 | import djcelery
322 |
323 | djcelery.setup_loader()
324 |
325 | $ cd {PROJECT PATH}
326 | $ ./manage.py makemigrations djcelery
327 | $ ./manage.py migrate djcelery
328 | ~~~~
329 |
330 |
331 | #### Celery command
332 |
333 | - Check rabbitmq is running. If it is not running, type
334 |
335 | ~~~~
336 | $ service rabbitmq-server start
337 | ~~~~
338 |
339 | - If you want to run celery with root permission, add following code at shell configuration file such as `~/.zshrc`
340 |
341 | ~~~~
342 | $ vi {SHELL CONFIGURATION FILE}
343 |
344 | export C_FORCE_ROOT='true'
345 |
346 | $ source {SHELL CONFIGURATION FILE}
347 | ~~~~
348 |
349 | ~~~~
350 | $ cd {PROJECT PATH}
351 | $ ./manage.py celeryd_detach --logfile=logs/celery_daemon.log --pidfile=logs/celery_daemon.pid # Start celery as daemon
352 | $ ./manage.py celery worker --loglevel=debug # Start celery with debug mode
353 | $ ./manage.py celery purge # Flush celery tasks
354 | $ ps auxww | grep 'celery worker' | grep -v grep | awk '{print $2}' | xargs kill -15 # Stop celery
355 | ~~~~
356 |
357 |
358 | #### Use cerely beat as cron task runner
359 |
360 | - Enroll tasks at Admin > Djcelery > Periodic tasks
361 |
362 | ~~~~
363 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
364 |
365 | CELERY_IMPORTS = ('{Application}.{Python file that contains cron tasks}',) (e.g. 'utils.cron')
366 | CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
367 | ~~~~
368 |
369 |
370 | #### Celery beat command
371 |
372 | ~~~~
373 | $ ./manage.py celery beat --logfile=logs/celery_beat.log --pidfile=logs/celery_beat.pid --detach # Start celery beat
374 | $ ps auxww | grep 'celery beat' | grep -v grep | awk '{print $2}' | xargs kill -15 # Stop celery beat
375 | ~~~~
376 |
377 |
378 | #### Configure New Relic settings
379 |
380 | - Visit newrelic.com and login
381 | - `APM` > `Python application`
382 | - Get license key
383 |
384 | ~~~~
385 | $ pip install newrelic
386 | $ mkdir -p {PROJECT PATH}/conf/newrelic/
387 | $ cd {PROJECT PATH}/conf/newrelic/
388 | $ newrelic-admin generate-config {LICENSE KEY} newrelic.ini
389 | $ vi {PROJECT PATH}/{PROJECT NAME}/wsgi.py
390 |
391 | import newrelic.agent
392 |
393 | newrelic.agent.initialize({PATH TO NEW RELIC CONFIGURATION}/newrelic.ini')
394 | application = newrelic.agent.wsgi_application()(application)
395 | ~~~~
396 |
397 | - Restart uWSGI
398 |
399 |
400 | #### Install Pillow for image processing
401 |
402 | ~~~~
403 | $ apt-get install imagemagick libjpeg-dev libfreetype6 libfreetype6-dev zlib1g-dev
404 |
405 | # 32bit : i386-linux-gnu, 64bit : x86_64-linux-gnu
406 | $ ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib
407 | $ ln -s /usr/lib/x86_64-linux-gnu/libfreetype.so /usr/lib
408 | $ ln -s /usr/lib/x86_64-linux-gnu/libz.so /usr/lib
409 |
410 | # Only for ubuntu 14.04 LTS version
411 | $ ln -s /usr/include/freetype2 /usr/include/freetype
412 |
413 | $ pip install pillow
414 | ~~~~
415 |
416 | - Check available list
417 |
418 |
419 | #### Install Django REST framework
420 |
421 | ~~~~
422 | $ pip install djangorestframework
423 | $ pip install markdown
424 | $ pip install django-filter
425 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
426 |
427 | INSTALLED_APPS += (
428 | 'rest_framework',
429 | )
430 | ~~~~
431 |
432 |
433 | #### Use django-silk *(live profiling and inspection tool)*
434 |
435 | ~~~~
436 | $ pip install django-silk
437 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
438 |
439 | # Django >= 1.10
440 | MIDDLEWARE = ['silk.middleware.SilkyMiddleware', ] + MIDDLEWARE
441 |
442 | # Django <= 1.9
443 | MIDDLEWARE_CLASSES = ('silk.middleware.SilkyMiddleware', ) + MIDDLEWARE_CLASSES
444 |
445 | INSTALLED_APPS += (
446 | 'silk',
447 | )
448 |
449 | $ cd {PROJECT PATH}
450 | $ ./manage.py makemigrations silk
451 | $ ./manage.py migrate silk
452 | ~~~~
453 |
454 | #### User JWT(Json Web Token) as authentication method in Django REST framework
455 |
456 | ~~~~
457 | $ pip install djangorestframework-jwt
458 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
459 |
460 | REST_FRAMEWORK = {
461 | ...
462 | 'DEFAULT_AUTHENTICATION_CLASSES': (
463 | ...
464 | 'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
465 | ...
466 | )
467 | }
468 |
469 | $ {PROJECT PATH}/{PROJECT NAME}/urls.py
470 |
471 | from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_token
472 |
473 | urlpatterns = [
474 | ...
475 | url(
476 | r'^api-token-auth/',
477 | obtain_jwt_token,
478 | ),
479 | url(
480 | r'^api-token-refresh/',
481 | refresh_jwt_token
482 | ),
483 | url(
484 | r'^api-token-verify/',
485 | verify_jwt_token
486 | ),
487 | ...
488 | ]
489 | ~~~~
490 |
491 | - Usage
492 | - Get token
493 | - End-point: `{PROJECT DOMAIN}/api-token-auth/`
494 | - HTTP method: `POST`
495 | - parameters: `{'username': {USERNAME}, 'password': {PASSWORD}}`
496 | - return: `{'token': {TOKEN}}`
497 | - Verify token
498 | - End-point: `{PROJECT DOMAIN}/api-token-verify/`
499 | - HTTP method: `POST`
500 | - parameters: `{'token': {EXISTING TOKEN}}`
501 | - return: `200 OK` or `400 Bad Request`
502 | - Refresh token
503 | - End-point: `{PROJECT DOMAIN}/api-token-refresh/`
504 | - HTTP method: `POST`
505 | - parameters: `{'token': {EXISTING TOKEN}}`
506 | - return: `{'token': {NEW TOKEN}}`
507 |
508 |
509 | #### Use django-cors-headers to enable Cross-Origin-Resouce-Sharing
510 |
511 | ~~~~
512 | $ pip install django-cors-headers
513 | $ vi {PROJECT PATH}/{PROJECT NAME}/settings.py
514 |
515 | INSTALLED_APPS = (
516 | ...
517 | 'corsheaders',
518 | ...
519 | )
520 |
521 | MIDDLEWARE = [
522 | ...
523 | 'corsheaders.middleware.CorsMiddleware',
524 | 'django.middleware.common.CommonMiddleware',
525 | ...
526 | ]
527 |
528 | CORS_ORIGIN_WHITELIST = (
529 | '*.mysite.com',
530 | )
531 |
--------------------------------------------------------------------------------