diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a019259b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +FROM node:8 +LABEL maintainer "Nitin Goyal , Luke Busstra " + +ENV NGINX_CODENAME stretch +ENV API_PORT 3001 + +# install requirements +RUN echo "deb http://nginx.org/packages/debian/ ${NGINX_CODENAME} nginx" >> /etc/apt/sources.list \ + && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y --assume-yes --allow-unauthenticated \ + gettext-base\ + bash \ + zip \ + unzip \ + wget \ + curl \ + nano \ + ca-certificates \ + nginx \ + nginx-module-image-filter + +# install PM2 +RUN npm install pm2 -g + +RUN mkdir -p /var/www \ + && cd /var/www \ + && mkdir -p cezerin2 + +# download project +ADD . /var/www/cezerin2 + +# Nginx config +COPY nginx/nginx.conf /etc/nginx/ +COPY nginx/default.conf.template /etc/nginx/conf.d/ + +# script to run Nginx and PM2 +COPY docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x "/usr/local/bin/docker-entrypoint.sh" + +# build project +RUN cd /var/www/cezerin2 \ + && npm i + +WORKDIR /var/www/cezerin2 + +EXPOSE 80 + +# start PM2 +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] diff --git a/config/server.js b/config/server.js index 1746616b..aca4020b 100644 --- a/config/server.js +++ b/config/server.js @@ -12,23 +12,19 @@ const dbUrl = module.exports = { // used by Store (server side) - apiBaseUrl: `http://localhost:3001/api/v1`, - - // used by Store (server and client side) - ajaxBaseUrl: `http://localhost:3001/ajax`, + apiBaseUrl: process.env.API_BASE_URL || `http://localhost:3001/api/v1`, // Access-Control-Allow-Origin - storeBaseUrl: `http://localhost:3000`, + storeBaseUrl: process.env.STORE_URL || `http://localhost:3000`, // used by API - adminBaseURL: process.env.ADMIN_BASE_URL || 'http://localhost:3003', + adminBaseURL: process.env.ADMIN_BASE_URL || 'http://localhost:3002', adminLoginPath: process.env.ADMIN_LOGIN_PATH || '/admin/login', // used by API to service assets - assetsBaseURL: process.env.ASSETS_BASE_URL || '', + assetsBaseURL: process.env.ASSETS_BASE_URL || 'http://localhost:3001', - apiListenPort: 3001, - storeListenPort: process.env.STORE_PORT || 3000, + apiListenPort: process.env.API_PORT || 3001, // used by API mongodbServerUrl: dbUrl, @@ -44,10 +40,10 @@ module.exports = { }, // key to sign tokens - jwtSecretKey: '-', + jwtSecretKey: process.env.JWT_SECRET_KEY || '-', // key to sign store cookies - cookieSecretKey: '-', + cookieSecretKey: process.env.COOKIE_SECRET_KEY || '-', // path to uploads categoriesUploadPath: 'public/content/images/categories', @@ -62,7 +58,7 @@ module.exports = { themeAssetsUploadUrl: '/assets/images', // store UI language - language: 'en', + language: process.env.LANGUAGE || 'en', // used by API orderStartNumber: 1000, diff --git a/config/store.js b/config/store.js deleted file mode 100644 index 34f20950..00000000 --- a/config/store.js +++ /dev/null @@ -1,6 +0,0 @@ -// config used by store client side only -module.exports = { - // store UI language - language: 'en', - ajaxBaseUrl: 'http://localhost:3001/ajax' -}; diff --git a/config/store.production.js b/config/store.production.js deleted file mode 100644 index 7fff640e..00000000 --- a/config/store.production.js +++ /dev/null @@ -1,6 +0,0 @@ -// config used by store client side only -module.exports = { - // store UI language - language: 'en', - ajaxBaseUrl: '/ajax' -}; diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 00000000..fe1c8c58 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +envsubst '${API_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf + +nginx +exec pm2 start process.json --no-daemon diff --git a/docs/single-instance/cezerin2-docker-compse.md b/docs/single-instance/cezerin2-docker-compse.md new file mode 100644 index 00000000..173445fc --- /dev/null +++ b/docs/single-instance/cezerin2-docker-compse.md @@ -0,0 +1,81 @@ +# Single Instance cezerin2 dockerfile and docker-entrypoint.sh + +* [dockerfile](#dockerfile) +* [docker-entrypoint.sh](#docker-entrypoint.sh) + +## dockerfile +```docker-compose +version: '3' + +services: + api: + build: + context: ./cezerin2 + env_file: .env + environment: + - DB_HOST=db + - STORE_URL=http://www.exampe.com + - API_BASE_URL=http://api.example.com/api/v1 + - AJAX_BASE_URL=http://api.example.com/ajax + - ASSETS_BASE_URL=http://asset.example.com + - ADMIN_BASE_URL=http://admin.example.com + ports: + - 3001:80 + volumes: + - ./cezerin2/public/content:/var/www/cezerin2/public/content + depends_on: + - db + restart: always + + store: + build: + context: ./cezerin2-store + environment: + - API_BASE_URL=http://api.example.com/api/v1 + - AJAX_BASE_URL=http://api.example.com/ajax + ports: + - 3000:80 + depends_on: + - db + - api + restart: always + + admin: + build: + context: ./cezerin2-admin + environment: + - API_BASE_URL=http://api.example.com/api/v1 + - API_WEB_SOCKET_URL=ws://api.example.com + ports: + - 3002:80 + depends_on: + - db + - api + restart: always + + proxy: + build: + context: ./proxy + environment: + - DOMAIN=example.com + - STORE_HOST=store + - ADMIN_HOST=admin + - API_HOST=api + ports: + - 80:80 + depends_on: + - db + - api + - admin + restart: always + + db: + image: mongo:3.4 + ports: + - 27017:27017 + volumes: + - ./db:/data/db + restart: always + +``` + diff --git a/docs/single-instance/cezerin2-proxy-dockerfile.md b/docs/single-instance/cezerin2-proxy-dockerfile.md new file mode 100644 index 00000000..765624e2 --- /dev/null +++ b/docs/single-instance/cezerin2-proxy-dockerfile.md @@ -0,0 +1,50 @@ +# Single Instance cezerin2-proxy dockerfile and docker-entrypoint.sh + +* [dockerfile](#dockerfile) +* [docker-entrypoint.sh](#docker-entrypoint.sh) + +## dockerfile +```dockerfile +FROM node:8 +LABEL maintainer "Luke Busstra " + +ENV NGINX_CODENAME stretch + + +# install requirements and NGINX +RUN echo "deb http://nginx.org/packages/debian/ ${NGINX_CODENAME} nginx" >> /etc/apt/sources.list \ + && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y --force-yes \ + gettext-base\ + bash \ + zip \ + unzip \ + wget \ + curl \ + nano \ + ca-certificates \ + nginx \ + nginx-module-image-filter + +# Nginx config +COPY nginx/nginx.conf /etc/nginx/ +COPY nginx/default.conf.template /etc/nginx/conf.d/ + +# script to run Nginx and PM2 +COPY docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x "/usr/local/bin/docker-entrypoint.sh" + +EXPOSE 80 + +# start env build and Nginx +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] +``` + +## docker-entrypoint.sh +```shell +#!/bin/sh +set -e + +envsubst '${DOMAIN} ${STORE_HOST} ${ADMIN_HOST} ${API_HOST} ${ASSET_HOST}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf + +nginx -g "daemon off;" +``` \ No newline at end of file diff --git a/docs/single-instance/cezerin2-proxy-nginx.md b/docs/single-instance/cezerin2-proxy-nginx.md new file mode 100644 index 00000000..e6fd5021 --- /dev/null +++ b/docs/single-instance/cezerin2-proxy-nginx.md @@ -0,0 +1,178 @@ +# Single Instance cezerin2-proxy nginx config + +* [nginx.conf](#nginx.conf) +* [default.conf.template](#default.conf.template) + +## nginx.conf +```nginx +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + keepalive_timeout 65; + sendfile on; + #tcp_nopush on; + #gzip on; + + include /etc/nginx/conf.d/*.conf; +} +``` + +## default.conf.template +```nginx +server { + # Dynamic image resizing server + listen 127.0.0.1:8888; + server_tokens off; + location ~ "^/resize/(?\w+)/(?\w+)/(?[1-9][0-9][0-9]{1}|[1][0-9][0-9][0-9]{1})/(?.+)$" { + alias /var/www/cezerin2/public/content/images/$entity/$id/$file; + image_filter_buffer 20M; + image_filter_jpeg_quality 85; + image_filter_interlace on; + image_filter resize $width -; + } +} + +# Cache rule for resized images +proxy_cache_path /tmp/nginx-images-cache2/ levels=1:2 keys_zone=images:10m inactive=30d max_size=5g use_temp_path=off; + +server { + listen 80; + server_name ${DOMAIN}; + + gzip on; + gzip_comp_level 2; + gzip_min_length 1024; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types application/x-javascript application/javascript application/xml application/json text/xml text/css text$ + + client_body_timeout 12; + client_header_timeout 12; + reset_timedout_connection on; + send_timeout 10; + server_tokens off; + client_max_body_size 50m; + + expires 1y; + access_log off; + log_not_found off; + + location / { + try_files $uri @proxy; + } + + location @proxy { + # Proxy to NodeJS + expires off; + proxy_pass http://${STORE_HOST}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +server { + listen 80; + server_name admin.${DOMAIN}; + + gzip on; + gzip_comp_level 2; + gzip_min_length 1024; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types application/x-javascript application/javascript application/xml application/json text/xml text/css text$ + + client_body_timeout 12; + client_header_timeout 12; + reset_timedout_connection on; + send_timeout 10; + server_tokens off; + client_max_body_size 50m; + + expires 1y; + access_log off; + log_not_found off; + + location / { + try_files $uri @proxy; + } + + location @proxy { + # Proxy to NodeJS + expires off; + proxy_pass http://${ADMIN_HOST}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} + +server { + listen 80; + server_name asset.${DOMAIN}; + + gzip on; + gzip_comp_level 2; + gzip_min_length 1024; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types application/x-javascript application/javascript application/xml application/json text/xml text/css text$ + + client_body_timeout 12; + client_header_timeout 12; + reset_timedout_connection on; + send_timeout 10; + server_tokens off; + client_max_body_size 50m; + + expires 1y; + access_log off; + log_not_found off; + + location / { + try_files $uri @proxy; + } + + location @proxy { + # Proxy to NodeJS + expires off; + proxy_pass http://${ASSET_HOST}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location ~ "^/images/(?\w+)/(?\w+)/(?[1-9][0-9][0-9]{1}|[1][0-9][0-9][0-9]{1})/(?.+)$" { + # /images/products/id/100/file.jpg >>> Proxy to internal image resizing server + proxy_pass http://127.0.0.1:8888/resize/$entity/$id/$width/$file; + proxy_cache images; + proxy_cache_valid 200 30d; + } +} +``` diff --git a/docs/single-instance/getting-started.md b/docs/single-instance/getting-started.md new file mode 100644 index 00000000..e25caa78 --- /dev/null +++ b/docs/single-instance/getting-started.md @@ -0,0 +1,183 @@ +# Getting Started with Single Instance + +* [Setup](#setup) +* [Run Cezerin2](#run-cezerin2) +* [Run Cezerin2 Admin](#run-cezerin2-admin) +* [Run Cezerin2 Store](#run-cezerin2-store) +* [Run Cezerin2 Proxy](#run-cezerin2-proxy) +* [Docker Compose](#docker-compose) + +## Setup + +from the root directory execute + + git clone https://github.com/Cezerin2/cezerin2-admin.git + +## Run MongoDB + +```shell +docker run --name store-db -v /var/www/store-db:/data/db -d mongo:latest +``` + + +## Run cezerin2 + +1. Clone Cezerin2 + +```shell +git clone https://github.com/Cezerin2/cezerin2.git +``` + +2. Build Cezerin2 + +```shell +docker build \ +-t cezerin2 \ +. +``` + +3. Run Cezerin2 + +```shell +docker run -d \ +--name cezerin2 \ +--link store-db:db \ +-p 3001:80 \ +-e DB_HOST=db \ +-e DB_PORT=27017 \ +-e DB_NAME=shop \ +-e DB_USER=user \ +-e DB_PASS=password \ +-e STORE_URL=http://www.exampe.com \ +-e API_BASE_URL=http://api.example.com/api/v1 \ +-e AJAX_BASE_URL=http://api.example.com/ajax \ +-e ASSETS_BASE_URL=http://api.example.com \ +-e ADMIN_BASE_URL=http://admin.example.com \ +-v /Users/LBus/development/Cezerin2/cezerin2/public/content:/var/www/cezerin2/public/content \ +cezerin2 +``` + +For local use change + - www.exampe.com to localhost:3000 + - api.example.com to localhost:3001 + - admin.example.com to localhost:3002 + + +## Run cezerin2 Admin + +1. Clone Cezerin2 Admin + +```shell +git clone https://github.com/Cezerin2/cezerin2-admin.git +``` + +2. Build Cezerin2 Admin + +```shell +docker build \ +-t cezerin2-admin \ +. +``` + +3. Run Cezerin2 Admin + +```shell +docker run -d \ +--name cezerin2-admin \ +--link cezerin2:cezerin2 \ +-p 3002:80 \ +-e API_BASE_URL=http://api.example.com/api/v1 +-e API_WEB_SOCKET_URL=ws://api.example.com +cezerin2-admin +``` + +## Run Cezerin2 Store + +1. Clone Cezerin2 Store + +```shell +git clone https://github.com/Cezerin2/cezerin2-store.git +``` + +2. Build cezerin2 Store + +```shell +docker build \ +-t cezerin2-store \ +. +``` + +3. Run Cezerin2 Store + +```shell +docker run -d \ +--name cezerin2-store \ +--link cezerin2:cezerin2 \ +-p 3002:80 \ +-e API_BASE_URL=http://api.example.com/api/v1 \ +-e AJAX_BASE_URL=http://api.example.com/ajax \ +cezerin2-store +``` + +For local use change + - api.example.com to cezerin2 + +## Build Run Cezerin2 Proxy + +1. Create follow folder structure + + cezerin2-admin # clone cezerin2-admin repo + ├── nginx # nginx cezerin2-admin config + | ├── nginx.conf # nginx cezerin2-admin config + │ └── default.conf # cezerin2-admin dockerfile + └── dockerfile # cezerin2-admin dockerfile + +[cezerin2-proxy dockerfile & docker-entrypoint](./cezerin2-proxy-dockerfile.md) + +[cezerin2-proxy nginx](./cezerin2-proxy-nginx.md) + +2. Build Cezerin2 Proxy + +```shell +docker build \ +-t cezerin2-proxy \ +. +``` + +3. Run Cezerin2 Proxy + +```shell +docker run -d \ +--name cezerin2-proxy \ +--link cezerin2:cezerin2 \ +--link cezerin2-admin:cezerin2-admin \ +--link cezerin2-store:cezerin2-store \ +-p 80:80 \ +-e DOMAIN=example.com \ +-e STORE_HOST=cezerin2-store \ +-e ADMIN_HOST=cezerin2-admin \ +-e API_HOST=cezerin2 \ +cezerin2-proxy +``` + +## Docker Compose + +setup project as: + . + ├── cezerin2 # clone cererin2 repo + │ ├── dockerfile # cezerin2 dockerfile + │ └── docker-entrypoint.sh # cezerin2 docker-entrypoint.sh + ├── cezerin2-admin # clone cezerin2-admin repo + │ ├── nginx # nginx cezerin2-admin config + │ | ├── nginx.conf # nginx cezerin2-admin config + │ │ └── default.conf # cezerin2-admin dockerfile + │ └── dockerfile # cezerin2-admin dockerfile + ├── cezerin2-store # clone cezerin2-store repo + │ ├── dockerfile # cezerin2-store dockerfile + │ └── docker-entrypoint.sh # cezerin2-store docker-entrypoint.sh + ├── proxy # New folder for proxy + │ └── dockerfile # proxy dockerfile + └── docker-compose.yml # Tools and utilities + + +[cezerin2 docker-compose](./cezerin2-docker-compose.md) diff --git a/nginx/default.conf.template b/nginx/default.conf.template new file mode 100644 index 00000000..1c2b8d19 --- /dev/null +++ b/nginx/default.conf.template @@ -0,0 +1,62 @@ +server { + # Dynamic image resizing server + listen 127.0.0.1:8888; + server_tokens off; + location ~ "^/resize/(?\w+)/(?\w+)/(?[1-9][0-9][0-9]{1}|[1][0-9][0-9][0-9]{1})/(?.+)$" { + alias /var/www/cezerin2/public/content/images/$entity/$id/$file; + image_filter_buffer 20M; + image_filter_jpeg_quality 85; + image_filter_interlace on; + image_filter resize $width -; + } +} + +# Cache rule for resized images +proxy_cache_path /tmp/nginx-images-cache2/ levels=1:2 keys_zone=images:10m inactive=30d max_size=5g use_temp_path=off; + +server { + listen 80; + server_name _; + + gzip on; + gzip_comp_level 2; + gzip_min_length 1024; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types application/x-javascript application/javascript application/xml application/json text/xml text/css text$ + + client_body_timeout 12; + client_header_timeout 12; + reset_timedout_connection on; + send_timeout 10; + server_tokens off; + client_max_body_size 50m; + + expires 1y; + access_log off; + log_not_found off; + root /var/www/cezerin2/public/content; + + location ~ "^/images/(?\w+)/(?\w+)/(?[1-9][0-9][0-9]{1}|[1][0-9][0-9][0-9]{1})/(?.+)$" { + # /images/products/id/100/file.jpg >>> Proxy to internal image resizing server + proxy_pass http://127.0.0.1:8888/resize/$entity/$id/$width/$file; + proxy_cache images; + proxy_cache_valid 200 30d; + } + + location / { + try_files $uri @proxy; + } + + location @proxy { + # Proxy to NodeJS + expires off; + proxy_pass http://127.0.0.1:${API_PORT}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 00000000..e069cdf4 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,30 @@ +load_module modules/ngx_http_image_filter_module.so; +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + keepalive_timeout 65; + sendfile on; + #tcp_nopush on; + #gzip on; + + include /etc/nginx/conf.d/*.conf; +} \ No newline at end of file