Skip to content

Production Environment

deby edited this page Mar 15, 2023 · 59 revisions

↑ Parent: More

← Previous: Migrate from MagiCircles1 to MagiCircles2

First time launch pre-requirements

  • Ensure that the following Website settings are properly set:
    • GITHUB_REPOSITORY
    • SITE_URL
    • SITE_STATIC_URL
    • DISQUS_SHORTNAME (create it here)
    • GOOGLE_ANALYTICS (create it here, be sure to click Show advanced options, then turn on the switch for Create a Universal Analytics property)
  • The following Website settings are not required, but highly recommended:
    • CORNER_POPUP_IMAGE
    • DONATE_IMAGE
    • DONATORS_STATUS_CHOICES
    • ABOUT_PHOTO
    • HASHTAGS
  • Check that you don't have any polluting file in your static files folder
  • Generate your flaticons here and add the following to the root of the static folder:
    • apple-touch-icon.png
    • favicon-16x16.png
    • favicon-32x32.png
    • favicon.ico
    • safari-pinned-tab.svg
  • The following images are set up:
    • avatar.png, game.png, 404.png, 500.png, 403.png
    • Banner for users birthdays (birthday.png)
    • Talking character in the corner (CORNER_POPUP_IMAGE and CORNER_POPUP_IMAGE_OVERFLOW)
  • Populate default staff configurations in ${PROJECT}/management/commands/populate_staffconfigurations_${PROJECT}.py
    from django.core.management.base import BaseCommand
    from magi.management.commands.populate_staffconfigurations import create
    from magi import models as magi_models
    
    class Command(BaseCommand):
        can_import_settings = True
    
        def handle(self, *args, **options):
            # Set up defaults for existing configurations
            magi_models.StaffConfiguration.objects.filter(key='about_image').update(value='about.png')
            magi_models.StaffConfiguration.objects.filter(key='about_the_website', i_language='en').update(value="""
    """)
            magi_models.StaffConfiguration.objects.filter(key='about_us', i_language='en').update(value="""
    """)
    
  • Link translations POEditor → GitHub
    • Commit empty files for all languages:
      NEWLANGS='es zh_Hans ru it fr de pl ja kr id vi zh_Hant pt pt_BR tr uk'
      for lang in $NEWLANGS; do mkdir -p $PROJECT/locale/$lang/LC_MESSAGES/ && touch $PROJECT/locale/$lang/LC_MESSAGES/django.po; done
      for lang in $NEWLANGS; do git add $PROJECT/locale/$lang/LC_MESSAGES/django.po; done
      git commit -m "Add new language(s) $NEWLANGS"
    • Go to POEditor setup page
    • For each language, link with POEditor:

      Make sure you check the box "Also get a .mo file with the same filename on export."
  • Set up contact@ email address:
    • Go to Gandi domains and add a forwarding address to all the managers + users who do "support"
    • Go to SES and verify the email address
    • Edit ${PROJECT}_project/settings.py to set the AWS_SES_RETURN_PATH
    • Edit ${PROJECT}/settings.py to set the CONTACT_EMAIL
    • All managers + users who do support should set up their Gmail to send from the contact address:
      • In the top right, click ⚙️ and then Settings.
      • Click the Accounts and import tab.
      • In the "Send mail as" section, click Add another email address.
      • In Name set {username} from {site} staff (example: db0 from Bandori Party staff)
      • In address put contact@{domain} (example: contact@bandori.party)
      • Check "Treat as an alias"
      • For SMTP Server, put smtp.gmail.com
      • For Username, your full Gmail address including @gmail.com
      • For password, provide an App Password generated in Google Accounts from here (for app select "Other (custom name)")
      • Leave Secured connection using TLS selected as is.
    • Make sure to test that everyone receives the email and can set from the email

Deploying a website to an EC2 instance

ℹ️ This guide assumes you're using EC2, RDS, SES, Cloudflare and TinyPNG. You may need to do things differently if you want a different setup.

ℹ️ This guide can be used when a website is launched for the first time or when it's migrated to a different instance (different size for example). It can be used for a new EC2 instance or an existing EC2 instance used for other Circles websites.

ℹ️ This guide uses emacs, but any editor works. If you use emacs, you may want to M-x electric-indent-mode before copy-pasting anything.

  1. Go to the EC2 console and create your instance with ubuntu server.

  2. Use ssh to connect to your instance.

    ssh -i your_key.pem ubuntu@ec2-somethingsomething.compute-1.amazonaws.com
  3. Set up your local environment variable corresponding to your project. See step 2 of Local setup.

  4. Work in a screen to be able to come back later + set some aliases:

    screen -S ${PROJECT}
    alias pm='python manage.py'
  5. Install / update local packages:

    sudo apt-get update
    sudo apt-get install git emacs mysql-client gcc nginx python-dev virtualenv uwsgi uwsgi-plugin-python libjpeg-dev libjpeg8-dev
    sudo apt-get install -f
    sudo apt-get autoremove
  6. Clone and configure the repository:

    git clone https://github.com/MagiCircles/${REPO}.git
    cd ${REPO}
  7. Create a virtual environment to isolate the package dependencies locally and install packages:

    virtualenv --python=`which python2` env
    source env/bin/activate
    pip install pip==9.0.1
    pip install -r requirements.txt && pip install --no-deps django-ses==1.0.2 && pip install boto3
  8. Configure NGINX:

    sudo emacs /etc/nginx/sites-enabled/default

    Copy-paste the following:

    server {
        listen 80;
        listen [::]:80 default_server ipv6only=on;
        server_name your.domain;
        client_max_body_size 500M;
        charset     utf-8;
    
        root /dev/null;
        location /favicon.ico {
            alias /home/ubuntu/RepoName/shortname/static/img/favicon.ico;
        }
    
        location / {
            include uwsgi_params;
            uwsgi_pass_header Server;
            uwsgi_param Host $http_host;
            uwsgi_intercept_errors off;
            uwsgi_param X-Real-IP $remote_addr;
            uwsgi_param X-Scheme $scheme;
            uwsgi_connect_timeout 20;
            uwsgi_read_timeout 300;
            uwsgi_pass 127.0.0.1:12345;
            add_header Cache-Control private;
        }
    }

    After copy-pasting, you'll need to replace the following terms:

    • your.domain with your domain name, such as bandori.party
    • 12345 with the port you want to use
    • RepoName with the name of the repo (example: BanGDream)
    • shortname with the short name of the project (example: bang)
  9. Configure uWSGI:

    sudo emacs /etc/uwsgi/apps-enabled/${PROJECT}.ini

    Copy-paste the following:

    [uwsgi]
    chdir=/home/ubuntu/RepoName/
    home=/home/ubuntu/RepoName/env/
    module=shortname_project.wsgi:application
    master=True
    env=DJANGO_SETTINGS_MODULE=shortname_project.settings
    max-requests=300
    socket = 127.0.0.1:12345
    protocol=uwsgi
    harakiri=30
    processes=4
    lazy-apps=True
    queue=200
    listen=128
    buffer-size=7000
    plugins=python

    After copy-pasting, you'll need to replace the following terms:

    • 12345 with the port you want to use
    • RepoName with the name of the repo (example: BanGDream)
    • shortname with the short name of the project (example: bang)
  10. Delete any polluting file accidentally created by emacs:

    sudo rm /etc/nginx/sites-enabled/default~ /etc/uwsgi/apps-enabled/${PROJECT}.ini~
  11. Configure your website:

    emacs ${PROJECT}_project/local_settings.py

    Copy-paste the following:

    STATIC_FILES_VERSION = '0'
    CONN_MAX_AGE = 100
    
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))
    
    DEBUG = False
    
    STATIC_UPLOADED_FILES_PREFIX = 'u/'
    
    STATIC_URL = '//i.your.domain/static/'
    
    SECRET_KEY = 'secretkey'
    
    ALLOWED_HOSTS = ['your.domain']
    
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    AWS_ACCESS_KEY_ID = 'aws_key'
    AWS_SECRET_ACCESS_KEY = 'aws_secret'
    AWS_STORAGE_BUCKET_NAME = 'i.your.domain'
    
    from boto.s3.connection import OrdinaryCallingFormat
    AWS_S3_CALLING_FORMAT = OrdinaryCallingFormat()
    
    EMAIL_BACKEND = 'django_ses.SESBackend'
    AWS_SES_REGION_NAME = 'aws_region'
    AWS_SES_REGION_ENDPOINT = 'email.aws_region.amazonaws.com'
    SERVER_EMAIL = 'emails-log@schoolido.lu'
    
    TINYPNG_API_KEY = 'tinpng_key'
    GITHUB_API_KEY = 'github_key'
    
    TWITTER_API_KEY = 'twitter_api_key'
    TWITTER_API_SECRET = 'twitter_api_secret'
    
    RECAPTCHA_PRIVATE_KEY = 'recaptcha_private_key'
    RECAPTCHA_PUBLIC_KEY = 'recaptcha_public_key'
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'shortname',
            'OPTIONS': {'charset': 'utf8mb4'},
            'USER': 'db_username',
            'PASSWORD': 'db_password',
            'HOST': 'db_host',
            'PORT': '3306',
        }
    }
    
    LOGGING = {
        'disable_existing_loggers': False,
        'version': 1,
        'handlers': {
            'console': {
                'class': 'logging.StreamHandler',
                'level': 'DEBUG',
            },
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler'
            },
        },
        'loggers': {
            '': {
                'handlers': ['console', 'mail_admins'],
                'level': 'DEBUG',
                'propagate': False,
            },
            'django.request': {
                'handlers': ['console', 'mail_admins'],
                'level': 'DEBUG',
                'propagate': True,
            },
            'django.db.backends.mysql': {
                'handlers': ['console', 'mail_admins'],
                'level': 'DEBUG',
            },
            'django.db': {
                'handlers': ['mail_admins'],
                'level': 'DEBUG',
            },
        },
    }

    After copy-pasting, you'll need to replace the following terms:

    • your.domain with your domain name, such as bandori.party
    • secretkey with a secret key which you can generate here
    • aws_key and aws_secret with your AWS key and secret
    • aws_region with the AWS region you use (example: us-east-1)
    • tinpng_key with your TinyPNG developer key
    • github_key with a GitHub token (can be retrieved here)
    • 'twitter_api_key' with a Twitter API key (A Twitter developer account is required, see here)
    • twitter_api_secret' (A Twitter developer account is required, see here)
    • 'recaptcha_private_key' (can be retrieved here)
    • 'recaptcha_public_key' (can be retrieved here)
    • shortname with the short name of the project (example: bang)
    • db_username with the database username you configured on RDS
    • db_password with your database password
    • db_host with your RDS host (example: something.abcdfefhr.us-east-1.rds.amazonaws.com)
  12. Install MySQL client:

    sudo apt-get install libmysqlclient-dev
    pip install mysql-python
  13. [Only if it's a new EC2 instance]

    *Assuming you have a security group configured in AWS

    1. Go to EC2 instance and change security group to the security group (right click / networking / change security group)

    2. Go to the security group and add mysql inbound with server ip

    3. Test if it worked:

      mysql -h something.abcdfefhr.us-east-1.rds.amazonaws.com -u root -p
  14. [Only if it's the first time a website is launched]

    1. Create the database:

      Replace shortname with the short name of the project (example: bang):

      CREATE DATABASE shortname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    2. Initialize the database:

      pm migrate
    3. Add an index on users page default ordering:

      mysql -h something.abcdfefhr.us-east-1.rds.amazonaws.com -u root -p

      Replace shortname with the short name of the project (example: bang):

      USE shortname;
      CREATE INDEX manual_auth_user_date_joined ON auth_user (date_joined);
    4. Configure Cloudflare domain to point to the server IP.

      Add a new record of type "A" with name your.domain and value the IP of the server.

      Configure important settings on CloudFlare:

       - Caching / Browser Cache Expiration / 1 year
       - SSL/TLS / Edge Certificates / Always Use HTTPS / On
      
    5. Create a new S3 bucket with the name i.your.domain where your.domain is your domain name, such as bandori.party

      1. Unselect all options that block public access.

      2. After creating the bucket, go to "Permissions" then "CORS configuration" and change to the following:

        <?xml version="1.0" encoding="UTF-8"?>
        <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
        <CORSRule>
            <AllowedOrigin>*</AllowedOrigin>
            <AllowedMethod>GET</AllowedMethod>
            <AllowedMethod>HEAD</AllowedMethod>
            <AllowedMethod>POST</AllowedMethod>
            <MaxAgeSeconds>3000</MaxAgeSeconds>
            <ExposeHeader>Content-Length</ExposeHeader>
            <AllowedHeader>Authorization</AllowedHeader>
        </CORSRule>
        </CORSConfiguration>
        

        If it asks for JSON:

                   [
           {
               "AllowedHeaders": [
                   "Authorization"
               ],
               "AllowedMethods": [
                   "GET",
                   "HEAD",
                   "POST"
               ],
               "AllowedOrigins": [
                   "*"
               ],
               "ExposeHeaders": [
                   "Content-Length"
               ],
               "MaxAgeSeconds": 3000
           }
        ]
    6. Generate the static files and upload them to the newly created S3 instance. This needs to be done on your local instance on your own computer. If you don't have one, follow Local setup.

      pm generate_css
      emacs ${PROJECT}_project/local_settings.py
      # ↑ add: STATIC_ROOT = 'collected'
      python manage.py collectstatic
      find . -name '.DS_Store' -type f -delete # Delete files created by OS X
      rm -r collected/uploaded # Delete uploaded files meant for tests

      Upload the content of the collected folder to the new S3 bucket in a folder called static.

      *All further commands will be once again on the production server, unless specified.

  15. Configure the static domain on Cloudflare to point to the URL of the S3 bucket.

     Add a new record with type "CNAME", name "i" and target the full URL of the S3 bucket (`i.your.domain.s3.amazonaws.com`). 
    
  16. Perform some website commands to create some required local files:

    pm generate_settings
    pm latlong
  17. Test if the website works on the production server:

    pm runserver
  18. If Staff configurations are enabled, populate the staff configurations:

    pm populate_staffconfigurations
  19. Load the configurations:

    sudo /etc/init.d/nginx restart
    sudo service uwsgi restart
  20. [Only if a site is moved to a different instance]

    1. Configure Cloudflare domain to point to the new server IP.

    2. Check that the traffic goes to the new instance:

      sudo tail -n 100 -f /var/log/uwsgi/app/${PROJECT}.log
      
  21. Try to access your new website to see if everything worked!

  22. Set up cron jobs to:

    • Check for images that need to be compressed and markdown that need to be rendered to HTML every minute (cron that acts like a queue)
    • Send email for unread notifications, every 2 hours
    • Generate the map with locations of the users, every day at midnight
    • Generate settings, every day at midnight
    • Reload the website with the new generated settings, every day at midnight + 10 minutes
    crontab -e
    # RepoName
    
    * * * * * /home/ubuntu/RepoName/env/bin/python /home/ubuntu/RepoName/manage.py async_db_updates >> /home/ubuntu/RepoName/async_cronjob.log 2>&1
    0 */2 * * * /home/ubuntu/RepoName/env/bin/python /home/ubuntu/RepoName/manage.py cron_notifications >> /home/ubuntu/RepoName/cronjob.log 2>&1
    0 0 * * * /home/ubuntu/RepoName/env/bin/python /home/ubuntu/RepoName/manage.py generate_settings >> /home/ubuntu/RepoName/settings_cronjob.log 2>&1
    0 0 1 * * rm /home/ubuntu/RepoName/cronjob.log /home/ubuntu/RepoName/async_cronjob.log /home/ubuntu/RepoName/settings_cronjob.log
    
    # All sites
    
    0 0 * * 0 sudo rm /tmp/tmp*
    10 0 * * * root service uwsgi reload
    

    After copy-pasting, you'll need to replace the following terms:

    • RepoName with the name of the repo (example: BanGDream)

    If you have multiple websites on the same EC2 instance, the last line only needs to be here once for all the website.

  23. Update this page to change the details of the "Current setup" section below.

  24. Done!

First time launch post-requirements

Useful commands

# Updating a site
pip install -r requirements.txt --upgrade && pip install --no-deps django-ses==1.0.2 && pip install boto3
git pull

# Update static files version
emacs ${PROJECT}_project/local_settings.py

# Reload a site after updating
sudo service uwsgi reload ${PROJECT}

# Check incoming requests log (uwsgi level)
sudo tail -n 100 -f /var/log/uwsgi/app/${PROJECT}.log

# Check incoming requests log (nginx level)
sudo tail -f /var/log/nginx/access.log

# Check asynchronous log
tail -n 2000 -f async_cronjob.log | \grep Info

# Connect to prod MySQL server from local computer through a prod server tunnel
# DB_HOST = your RDS host (example: something.abcdfefhr.us-east-1.rds.amazonaws.com)
# SERVER_HOST = ec2-somethingsomething.compute-1.amazonaws.com
ssh -i PEM_FILE_HERE -N -L 3306:DB_HOST:3306 ubuntu@SERVER_HOST
mysql -u root -p -h 127.0.0.1

Major update checklist

  • Local: pm generate_css
  • S3: upload generated CSS
  • S3: Check if the Javascript files for MagiCircles have been updated, upload them again if needed
  • S3: Check if the Javascript files for the site have been updated, upload them again if needed
  • S3: Check if new images have been added or updated for MagiCircles, upload them
  • S3: Check if new images have been added or updated for the site, upload them
  • Prod server: pip install -r requirements.txt --upgrade && pip install --no-deps django-ses==1.0.2 && pip install boto3
  • Prod server: git pull
  • Prod server: Update ${PROJECT}_project/local_settings.py to update the STATIC_FILES_VERSION
  • Prod server: pm migrate
  • Prod server: pm generate_settings
  • Prod server: sudo service uwsgi reload ${PROJECT}
  • Prod server: sudo tail -n 100 -f /var/log/uwsgi/app/${PROJECT}.log

Current setup

Updated: April 11th, 2022

EC2 instances

Domain Server code name Size Region MagiCircles version
bandori.party kasumi t2.large us-east-1d 2
bandori.org kasumi t2.large us-east-1d 2
starlight.academy ichie t2.large us-east-1b 2
idol.st ichie t2.large us-east-1b 2
schoolido.lu ichie t2.large us-east-1b N/A
cinderella.pro layla t2.small us-east-1b 1
frgl.db0.company layla t2.small us-east-1b 0
stardust.run layla t2.small us-east-1b 1
maji.love layla t2.small us-east-1b 2
shiny.schoolido.lu layla t2.small us-east-1b 2
ac.db0.company layla t2.small us-east-1b 2
starlet.db0.company layla t2.small us-east-1b 2

S3 buckets

All buckets are in US East (N. Virginia).

Domain Storage used
i.bandori.party 131.7G
i.idol.st 89.2G
i.schoolido.lu 32.4G
i.cinderella.pro 5.0G
i.starlight.academy 4.6G
i-frgl.db0.company 1.2G
i-starlet.db0.company 922.7M
i-ac.db0.company 406.2M
i.stardust.run 52.1M
i.maji.love 29.5M

DBS databases

DB name DB Size
schoolidolapi 4.6G
bang 1.7G
cpro 280M
idolstory 257M
stardustrun 120M
starlight 52M
starlet 24M
frgl 11M
ac 3M
majilove 3M
sukutomo 1M

→ Next: Flaticon

Appendix

Sukutomo production

screen -S schoolidolu
alias pm='python manage.py'
git clone https://github.com/MagiCircles/SchoolIdolAPI.git
cd SchoolIdolAPI
virtualenv env
source env/bin/activate
pip install pip==9.0.1
pip install -r requirements.txt
pip install --no-deps django-ses==1.0.2
pip install boto3
pip install mysql-python
sudo emacs /etc/nginx/sites-enabled/default
server {
        listen 80;
        server_name schoolido.lu www.schoolido.lu;
        client_max_body_size 500M;
        root /dev/null;
        location /favicon.ico {
                alias /home/ubuntu/SchoolIdolAPI/web/static/favicon.ico;
        }

        location /robots.txt {
                alias /home/ubuntu/SchoolIdolAPI/web/static/robots.txt;
        }

        location /contest/ {
                if ($http_user_agent = "") { return 403; }
                if ($http_user_agent = "python-requests") { return 403; }
                if ($http_user_agent = "python-requests/2.10.0") { return 403; }
                include uwsgi_params;
                uwsgi_pass_header Server;
                uwsgi_param Host $http_host;
                uwsgi_intercept_errors off;
                uwsgi_param X-Real-IP $remote_addr;
                uwsgi_param X-Scheme $scheme;
                uwsgi_connect_timeout 20;
                uwsgi_read_timeout 300;
                uwsgi_pass 127.0.0.1:12346;
                add_header Cache-Control private;
        }
        location / {
                include uwsgi_params;
                uwsgi_pass_header Server;
                uwsgi_param Host $http_host;
                uwsgi_intercept_errors off;
                uwsgi_param X-Real-IP $remote_addr;
                uwsgi_param X-Scheme $scheme;
                uwsgi_connect_timeout 20;
                uwsgi_read_timeout 300;
                uwsgi_pass 127.0.0.1:12346;
                add_header Cache-Control private;
        }
        location /static/ {
                root /home/ubuntu/SchoolIdolAPI/web/;
        }

        location /contest/static/ {
                alias /home/ubuntu/SchoolIdolContest/schoolidolcontest/static/;
                autoindex on;
        }
}
sudo emacs /etc/uwsgi/apps-enabled/schoolidolu.ini
[uwsgi]
chdir=/home/ubuntu/SchoolIdolAPI/
home=/home/ubuntu/SchoolIdolAPI/env/
module=schoolidolapi.wsgi:application
master=True
env=DJANGO_SETTINGS_MODULE=schoolidolapi.settings
max-requests=1200
socket = 127.0.0.1:12346
protocol=uwsgi
harakiri=60
processes=6
lazy-apps=True
queue=900
listen=128
buffer-size=9000
plugins=python
sudo rm /etc/nginx/sites-enabled/default~ /etc/uwsgi/apps-enabled/schoolidolu.ini~
scp EXISTING_LOCAL_SETTINGS.py NEWSERVER:schoolidolapi/local_settings.py
pm generate_settings
pm latlong

# Test:
pm runserver

crontab -e
# Schoolido.lu

0 */2 * * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py cron_notifications >> /home/ubuntu/cronjob.log 2>&1
# 0 * * * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py drown_negativity >> /home/ubuntu/cronjob.log 2>&1
0 0 * * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py latlong >> /home/ubuntu/latlong_cronjob.log 2>&1
0 0 * * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py update_cards_owners >> /home/ubuntu/cronjob.log 2>&1
0 0 * * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py update_accounts_rankings >> /home/ubuntu/cronjob.log 2>&1
0 0 * * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py generate_settings >> /home/ubuntu/settings_cronjob.log 2>&1
0 0 1 * * /home/ubuntu/SchoolIdolAPI/env/bin/python /home/ubuntu/SchoolIdolAPI/manage.py update_cards_join_cache >> /home/ubuntu/update_cards_join_cache.log 2>&1

0 0 1 * * rm -f /home/ubuntu/cronjob.log /home/ubuntu/latlong_cronjob.log /home/ubuntu/settings_cronjob.log /home/ubuntu/update_cards_join_cache.log
# Reload:
sudo /etc/init.d/nginx restart
sudo service uwsgi restart

# Update Cloudflare then check for traffic:
sudo tail -n 100 -f /var/log/uwsgi/app/schoolidolu.log

frgl production

screen -S frgl
alias pm='python manage.py'
git clone https://github.com/MagiCircles/frgl.git
cd frgl
virtualenv env
source env/bin/activate
pip install pip==9.0.1
pip install -r requirements.txt
sudo emacs /etc/nginx/sites-enabled/default
# EITHER
npm install -g bower
bower install
# OR
scp -r frgl/web/static/bower NEWSERVER:frgl/web/static/
# EITHER
lessc frgl/web/static/less/style.less frgl/web/static/css/style.css
# OR
scp frgl/web/static/css/style.css NEWSERVER:frgl/web/static/css/style.css
server {
       listen 80;
       server_name fr.gl frgl.db0.company;
        location / {
                include uwsgi_params;
                uwsgi_pass_header Server;
                uwsgi_param Host $http_host;
                uwsgi_intercept_errors off;
                uwsgi_param X-Real-IP $remote_addr;
                uwsgi_param X-Scheme $scheme;
                uwsgi_connect_timeout 20;
                uwsgi_read_timeout 20;
                uwsgi_pass 127.0.0.1:12347;
                add_header Cache-Control private;
        }

       location /static/ {
                root /home/ubuntu/frgl/web/;
       }
}
sudo emacs /etc/uwsgi/apps-enabled/frgl.ini
[uwsgi]
chdir=/home/ubuntu/frgl/
home=/home/ubuntu/frgl/env/
module=frgl.wsgi:application
master=True
env=DJANGO_SETTINGS_MODULE=frgl.settings
vacuum=True
max-requests=5000
socket = 127.0.0.1:12347
protocol=uwsgi
harakiri=15
processes=2
sudo rm /etc/nginx/sites-enabled/default~ /etc/uwsgi/apps-enabled/frgl.ini~
scp EXISTING_LOCAL_SETTINGS.py NEWSERVER:schoolidolapi/local_settings.py

# Test:
pm runserver

I. Introduction

II. Tutorials

  1. Collections
    1. MagiModel
    2. MagiCollection
    3. MagiForm
    4. MagiFiltersForm
    5. MagiFields
  2. Single pages
  3. Configuring the navbar

III. References

IV. Utils

V. Advanced tutorials

VI. More

Clone this wiki locally