diff --git a/.gitignore b/.gitignore
index b8a48286d71a54c4c7ffcdde683791fc3ecd0fd8..320a1ab2d7e059389dd2084a6548325cdcac9c80 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,174 +1,9 @@
 
-# Created by https://www.gitignore.io/api/macos,django,virtualenv,visualstudiocode
-# Edit at https://www.gitignore.io/?templates=macos,django,virtualenv,visualstudiocode
-
-### Django ###
-*.log
-*.pot
-*.pyc
-__pycache__/
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-media
-
-# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
-# in your Git repository. Update and uncomment the following line accordingly.
-# <django-project-name>/staticfiles/
-
-### Django.Python Stack ###
-# Byte-compiled / optimized / DLL files
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-pip-wheel-metadata/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-.hypothesis/
-.pytest_cache/
-
-# Translations
-*.mo
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# pyenv
-.python-version
-
-# pipenv
-#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-#   However, in case of collaboration, if having platform-specific dependencies or dependencies
-#   having no cross-platform support, pipenv may install dependencies that don't work, or not
-#   install all needed dependencies.
-#Pipfile.lock
-
-# celery beat schedule file
-celerybeat-schedule
-
-# SageMath parsed files
-*.sage.py
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# Mr Developer
-.mr.developer.cfg
-.project
-.pydevproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-### macOS ###
-# General
-.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-.com.apple.timemachine.donotpresent
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-### VirtualEnv ###
-# Virtualenv
-# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
-[Bb]in
-[Ii]nclude
-[Ll]ib
-[Ll]ib64
-[Ll]ocal
-[Ss]cripts
-pyvenv.cfg
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-pip-selfcheck.json
+# Created by https://www.gitignore.io/api/visualstudiocode
+# Edit at https://www.gitignore.io/?templates=visualstudiocode
 
 ### VisualStudioCode ###
 .vscode
-.vscode/*
 !.vscode/settings.json
 !.vscode/tasks.json
 !.vscode/launch.json
@@ -178,4 +13,4 @@ pip-selfcheck.json
 # Ignore all local history of files
 .history
 
-# End of https://www.gitignore.io/api/macos,django,virtualenv,visualstudiocode
+# End of https://www.gitignore.io/api/visualstudiocode
\ No newline at end of file
diff --git a/README.md b/README.md
index 7067ec03df771fb0ca4616ccfafc9b945bafd105..807ab0849d80e7fb20acbfe79690951454284cc4 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,7 @@
-Grader NG
+# Sofita
 
 ```
-docker run --rm -d -p 6379:6379 --name test-redis redis
+archive -> archive
+graderng -> web and backend
+gradersdaplugin -> plugin for moodle
 ```
-
-```
-docker run --rm -d -p 27017:27017 --name=test-mongo mongo
-```
-
-```
-celery -A graderng worker --loglevel=info
-```
-
-## Requirements
-
-Use `sqlparse==0.2.4`
diff --git a/graderng/.dockerignore b/graderng/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..b8a48286d71a54c4c7ffcdde683791fc3ecd0fd8
--- /dev/null
+++ b/graderng/.dockerignore
@@ -0,0 +1,181 @@
+
+# Created by https://www.gitignore.io/api/macos,django,virtualenv,visualstudiocode
+# Edit at https://www.gitignore.io/?templates=macos,django,virtualenv,visualstudiocode
+
+### Django ###
+*.log
+*.pot
+*.pyc
+__pycache__/
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+media
+
+# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
+# in your Git repository. Update and uncomment the following line accordingly.
+# <django-project-name>/staticfiles/
+
+### Django.Python Stack ###
+# Byte-compiled / optimized / DLL files
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# pyenv
+.python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### VirtualEnv ###
+# Virtualenv
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
+[Bb]in
+[Ii]nclude
+[Ll]ib
+[Ll]ib64
+[Ll]ocal
+[Ss]cripts
+pyvenv.cfg
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+pip-selfcheck.json
+
+### VisualStudioCode ###
+.vscode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+
+# End of https://www.gitignore.io/api/macos,django,virtualenv,visualstudiocode
diff --git a/graderng/.gitignore b/graderng/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b8a48286d71a54c4c7ffcdde683791fc3ecd0fd8
--- /dev/null
+++ b/graderng/.gitignore
@@ -0,0 +1,181 @@
+
+# Created by https://www.gitignore.io/api/macos,django,virtualenv,visualstudiocode
+# Edit at https://www.gitignore.io/?templates=macos,django,virtualenv,visualstudiocode
+
+### Django ###
+*.log
+*.pot
+*.pyc
+__pycache__/
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+media
+
+# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
+# in your Git repository. Update and uncomment the following line accordingly.
+# <django-project-name>/staticfiles/
+
+### Django.Python Stack ###
+# Byte-compiled / optimized / DLL files
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# pyenv
+.python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### VirtualEnv ###
+# Virtualenv
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
+[Bb]in
+[Ii]nclude
+[Ll]ib
+[Ll]ib64
+[Ll]ocal
+[Ss]cripts
+pyvenv.cfg
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+pip-selfcheck.json
+
+### VisualStudioCode ###
+.vscode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+
+# End of https://www.gitignore.io/api/macos,django,virtualenv,visualstudiocode
diff --git a/graderng/Dockerfile b/graderng/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..076c37a25a2ef22514140b7d63d4caeb9ac00e02
--- /dev/null
+++ b/graderng/Dockerfile
@@ -0,0 +1,18 @@
+FROM openjdk:8-alpine3.9
+
+RUN apk update \
+    && apk add --no-cache bash git make gcc libcap-dev musl-dev diffutils \
+    python3 py3-pillow
+
+ENV ISOLATE_VERSION v1.8.1
+RUN git clone --branch $ISOLATE_VERSION --depth 1 https://github.com/ioi/isolate \
+    && cd isolate \
+    && make install
+
+RUN mkdir /graderng
+COPY . /graderng
+WORKDIR /graderng
+
+RUN pip3 install -r requirements.txt
+
+ENTRYPOINT ["./entrypoint.sh"]
diff --git a/graderng/README.md b/graderng/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0a3f5c95ca6053bc58db82ac6a2f80e771e78083
--- /dev/null
+++ b/graderng/README.md
@@ -0,0 +1,116 @@
+# Grader-NG
+
+Data Structures and Algorithms Grader
+
+## Development
+
+1. Make sure Docker already installed and virtual environment already created.
+
+1. Install Pillow and its dependencies.
+
+   ```
+   pip install Pillow
+   ```
+
+1. Install all requirements.
+
+   ```
+   pip install -r requirements.txt
+   ```
+
+1. Run MongoDB.
+
+   ```
+   docker run --rm -d -p 27017:27017 --name=test-mongo mongo
+   ```
+
+1. Run Redis.
+
+   ```
+   docker run --rm -d -p 6379:6379 --name test-redis redis
+   ```
+
+1. Run worker.
+
+   ```
+   celery -A graderng worker --loglevel=info
+   ```
+
+## Production
+
+1. Install `docker` and `docker-compose`.
+
+1. Create `.env` file.
+
+   ```
+   DJANGO_SECRET_KEY=thisissecretkey
+   DJANGO_ENV=debug
+   DJANGO_MEDIA_LOCATION=/home/user/blablabla
+
+   MONGO_DATA_LOCATION=/home/user/mongo/gogogogo
+   MONGO_DBNAME=sofita
+   MONGO_USERNAME=mongousername
+   MONGO_PASSWORD=mongopassword
+   MONGO_HOST=mongo
+   MONGO_PORT=27017
+
+   REDIS_PASSWORD=redispwd
+   REDIS_HOST=redis
+   REDIS_PORT=6379
+
+   SCELE_URL=http://172.20.0.1/webservice/rest/server.php
+   SCELE_TOKEN=887bfe50daa8b8e518dd38e3832199b6
+   ```
+
+1. Run all services.
+
+   ```
+   docker-compose up -d
+   ```
+
+1. Create superuser.
+
+   ```
+   docker-compose exec web python3 manage.py createsuperuser
+   ```
+
+1. Generate token for SCELE.
+
+1. Add `grader_url` and `grader_token` variable to `config.php` at SCELE.
+
+   ```
+   $CFG->grader_url = "<grader_url>"
+   $CFG->grader_token = "<grader_token>"
+   ```
+
+## Apache
+
+1. Enable proxy.
+
+   ```
+   sudo a2enmod proxy
+   sudo service apache2 restart
+   ```
+
+1. Modify apache2 config `/etc/apache2/sites-available/000-default.conf`.
+
+   ```
+   <VirtualHost *:80>
+       ProxyPreserveHost On
+
+       ProxyPass / http://127.0.0.1:8080/
+       ProxyPassReverse / http://127.0.0.1:8080/
+   </VirtualHost>
+   ```
+
+1. Restart service.
+
+   ```
+   sudo service apache2 restart
+   ```
+
+## Important Notes
+
+1. Use `sqlparse==0.2.4`
+2. Server cannot access internet. Use `squid` to create proxy.
+3. Server use [ouroboros](https://github.com/pyouroboros/ouroboros) to update container automatically.
diff --git a/graderng/app/__init__.py b/graderng/app/__init__.py
index edf4a77dbeeba263ca32eb541e0f88f240b1f469..58d70c0eabbaa815f8fe2446843f768e8b7db57c 100644
--- a/graderng/app/__init__.py
+++ b/graderng/app/__init__.py
@@ -4,4 +4,7 @@ from django.conf import settings
 
 
 redis_connection_pool = redis.ConnectionPool(
-    host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=1)
+    host=settings.REDIS_HOST,
+    port=settings.REDIS_PORT,
+    password=settings.REDIS_PASSWORD,
+    db=1)
diff --git a/graderng/docker-compose.yml b/graderng/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6120e98ec83d230fa28a2340e1165fe2627bdb8f
--- /dev/null
+++ b/graderng/docker-compose.yml
@@ -0,0 +1,38 @@
+version: "3.7"
+services:
+  web:
+    build: .
+    depends_on:
+      - redis
+      - mongo
+    env_file: .env
+    ports:
+      - 8080:8080
+    privileged: true
+    volumes:
+      - ${DJANGO_MEDIA_LOCATION}:/graderng/media
+
+  worker:
+    build: .
+    depends_on:
+      - redis
+      - mongo
+      - web
+    command: ["celery"]
+    env_file: .env
+    privileged: true
+    volumes:
+      - ${DJANGO_MEDIA_LOCATION}:/graderng/media
+
+  redis:
+    image: redis:5.0.6
+    command: redis-server --requirepass ${REDIS_PASSWORD}
+
+  mongo:
+    image: mongo:4.2.1
+    environment:
+      MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME}
+      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
+      MONGO_INITDB_DATABASE: ${MONGO_DBNAME}
+    volumes:
+      - ${MONGO_DATA_LOCATION}:/data/db
diff --git a/graderng/entrypoint.sh b/graderng/entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ccde3a1922c88660b07380930075de73ceaedad2
--- /dev/null
+++ b/graderng/entrypoint.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+if [ "$1" == "celery" ]; then
+    celery -A graderng worker
+else
+    python3 manage.py collectstatic --noinput
+    python3 manage.py migrate
+    gunicorn graderng.wsgi --workers 3 --bind 0.0.0.0:8080
+fi
diff --git a/graderng/graderng/settings.py b/graderng/graderng/settings.py
index e7396354c1dd6d0af762130b1090be124d307b88..1d102af61cc9e3b4419fb8b0d1cbd8011a617111 100644
--- a/graderng/graderng/settings.py
+++ b/graderng/graderng/settings.py
@@ -21,7 +21,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 # SECURITY WARNING: keep the secret key used in production secret!
 SECRET_KEY = os.environ.get(
-    'SECRET_KEY', '#d6a5ogl)__t+h8!jx)$0vi)wk7znxscg)58hm+ljncg=@^j6k')
+    'DJANGO_SECRET_KEY', '#d6a5ogl)__t+h8!jx)$0vi)wk7znxscg)58hm+ljncg=@^j6k')
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = (os.environ.get("DJANGO_ENV", "debug") == "debug")
@@ -46,6 +46,9 @@ INSTALLED_APPS = [
 
 MIDDLEWARE = [
     'django.middleware.security.SecurityMiddleware',
+
+    'whitenoise.middleware.WhiteNoiseMiddleware',
+
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
@@ -81,7 +84,11 @@ WSGI_APPLICATION = 'graderng.wsgi.application'
 DATABASES = {
     'default': {
         'ENGINE': 'djongo',
-        'NAME': 'test-mongo',
+        'NAME': os.environ.get('MONGO_DBNAME', 'test-mongo'),
+        'USER': os.environ.get('MONGO_USERNAME'),
+        'PASSWORD': os.environ.get('MONGO_PASSWORD'),
+        'HOST': os.environ.get('MONGO_HOST'),
+        'PORT': int(os.environ.get('MONGO_PORT', 27017))
     }
 }
 
@@ -144,17 +151,17 @@ FILEBROWSER_MAX_UPLOAD_SIZE = 100 * 1024 * 1024
 
 # Redis
 
-REDIS_HOST = "localhost"
+REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD")
 
-REDIS_PORT = 6379
+REDIS_HOST = os.environ.get("REDIS_HOST", "localhost")
 
-REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD")
+REDIS_PORT = os.environ.get("REDIS_PORT", 6379)
 
 
 # Celery
 
-CELERY_BROKER_URL = os.environ.get(
-    "CELERY_BROKER_URL", "redis://localhost:6379/0")
+CELERY_BROKER_URL = "redis://:{}@{}:{}/0".format(
+    REDIS_PASSWORD, REDIS_HOST, REDIS_PORT)
 
 
 # SCELE
diff --git a/graderng/requirements.txt b/graderng/requirements.txt
index b538ada1faef1a4d74418edcba37f06802b61ef7..76bcda1768d80cea0ec626abe8478f4ce6e07e46 100644
--- a/graderng/requirements.txt
+++ b/graderng/requirements.txt
@@ -3,7 +3,8 @@ django-filebrowser-no-grappelli==3.7.8
 Django==2.2.6
 djangorestframework==3.10.3
 djongo==1.2.36
-Pillow==6.2.1
+gunicorn==20.0.0
 redis==3.3.11
 requests==2.22.0
 sqlparse==0.2.4
+whitenoise==4.1.4