---
# System prepended metadata

title: Sysmaker Docker Support
tags: [Docker, Sysmaker, docker-compose, Dockerfile]

---

# Sysmaker Docker Support
###### tags: `Sysmaker` `Docker` `Dockerfile` `docker-compose`

[TOC]

## About Sysmaker
* We ars **Sysmaker team** from *EPL, NTHU*
* Find us [**`@Sysmaker.Org`**](https://sysmaker.org) & [**`@Sysmaker GitHub`**](https://github.com/sysmaker-org)
    + We haven't published our source code yet
    + However, our production docker images are available @[**Docker Hub**](https://hub.docker.com/u/sysmaker)

## About Docker
> **`TL;DR`** **Visit Sysmaker [*`GitHub Repo`*](https://github.com/Sysmaker-Org/Docker) to trace our code** [color=red]
* Run Sysmaker (refer @[`GitHub`](https://github.com/Sysmaker-Org/Sysmaker-Docker_Images#run) for further info)
  1. `$ ./1-up.sh` (sysmaker/syamker-app & api)
  2. `$ ./1-up.sh single` (sysmaker/sysmaker)
* The docker image categories we are offering now *(Apr 2020 ~)*
    + There are stable **`master`** branch and developing **`feature`** branch in our workflow 
    + **`Image for Mainline`**
        :::success
        1. **`:master-*`**: the **testing passed** versions
        2. **`:latest`**: the newest *`master-`* version
        3. **`:prod`**: the newest *stable `master-` version* for mid-term production
        4. **`:vXX.YY.ZZ`**: the *stable `prod` versions* which *deserve version tags* :D
        :::
    + **`Image under Development`**
        :::info
        1. **`:dev`**: the newest *`feature-`* version (specific feature image is NOT provided)
        :::
        - :::warning
            * <span style="color:red">**`sysmaker/sysmaker-env`** use **`:latest`** for both *`master-*`* and *`feature-*`* branches</span> (but still having `:dev`)
                + This is by design for GitLab CI so that we can always use the `latest` tag even when we're on the `feature branch`
                + Use **`master-*`** tags to make sure you're using the correct environment
          :::
* In order to make use of our images, some `docker-compose*.yml`, `Dockerfile*`, and `*.conf` are provided as follows
    + *Dockerfile*
        1. [**`sysmaker/sysmaker-env`**](#sysmakersysmaker-env)
        2. [**`the rest`**](#sysmakersysmaker-sysmakersysmaker-app-and-sysmakersysmaker-api)
    + *docker-compose.yml*
        1. [**`environment variables`**](#env)
        2. [**`sysmaker/sysmaker (single)`**](#sysmakersysmaker-single)
        3. [**`sysmaker/sysmaker-app&api (normal)`**](#sysmakersysmaker-app-and-sysmakersysmaker-api-normal)
    + *(Nginx) Configs*
        1. [**`Angular (sysmaker-app)`**](#appconf)
        2. [**`Sysmaker normal (APP + API + Nginx)`**](#normalhttpsconf)
        3. [**`Sysmaker single`**](#singlehttpsconf)
        4. [**`Cloudflare Proxy IP Restore`**](#restore-ipcloudflare)
* *CHANGELOG*
    + **`master-0012-4045ddb`~ `now`** [time=Apr 2, 2020] [color=red]
* Folder structure
    + ```bash=
      ├── 0-build.sh
      ├── 1-up.sh
      ├── 2-down.sh
      ├── 3-push.sh
      │
      ├── .docker-compose.env.yml  # for `sysmaker/sysmaker-env`
      ├── .Dockerfile-env
      ├── .env  # specify base image versions
      │
      ├── docker-compose.gitlab-ci.yml  # for GitLab CI to build images
      ├── docker-compose.single.yml  # single
      ├── docker-compose.yml  # app and api (normal)
      ├── Dockerfile
      │
      └── misc
          ├── nginx-confd
          │   ├── app.conf  # for Nginx to serve Angular
          │   ├── nginx.http.conf  # just remove `https` part
          │   ├── nginx.https.conf
          │   ├── single.http.conf
          │   └── single.https.conf
          │
          └── ssl
              ├── restore-ip.cloudflare
              ├── sysmaker.crt  # Use your own SSL certificate
              └── sysmaker.key  # Ibid.
      ```


### Dockerfile
> `master-0012-4045ddb` ~ `now`
#### [**`sysmaker/sysmaker-env`**](https://github.com/Sysmaker-Org/Docker/blob/master/.Dockerfile-env)
```dockerfile=
ARG IMAGE_CYPRESS=cypress/base:12.16.1
FROM $IMAGE_CYPRESS
LABEL maintainer="LouisSung <ls@sysmaker.org>" \
      description="Sysmaker environment for ci and build (with Cypress, NPM, and Docker)"

ARG IMAGE_CYPRESS
WORKDIR /sysmaker
COPY sysmaker/package*.json ./
COPY misc/pages/* ./pages/

RUN echo "Image: $IMAGE_CYPRESS" \
    && apt-get update && apt-get install -y --no-install-recommends \
         bash bc curl jq git rsync tree libcanberra-gtk3-module \
         apt-transport-https ca-certificates gnupg2 software-properties-common \
    && curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - \
    && add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" \
    && apt-get update && apt-get install -y --no-install-recommends \
         docker-ce=5:19.03.8~3-0~debian-buster docker-ce-cli=5:19.03.8~3-0~debian-buster containerd.io \
    && curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
    && chmod +x /usr/local/bin/docker-compose \
    && rm -rf /var/lib/apt/lists/* \
    \
    && npm install --ignore-scripts --no-audit --loglevel info \
    && npm audit fix --ignore-scripts --verbose \
    && npm run postinstall \
    && $(npm bin)/cypress install

SHELL ["/bin/bash", "-c"]
CMD ["bash", "-c", "exit 0"]
```

#### [**`sysmaker/sysmaker`**, **`sysmaker/sysmaker-app`**, and **`sysmaker/sysmaker-api`**](https://github.com/Sysmaker-Org/Docker/blob/master/.Dockerfile-env)
```dockerfile=
# ===== default images =====
ARG IMAGE_SYSMAKER_ENV=sysmaker/sysmaker-env:latest
ARG IMAGE_NODE=node:lts-alpine
ARG IMAGE_NGINX=nginx:alpine

# ===== build stage =====
FROM $IMAGE_SYSMAKER_ENV AS base
LABEL sysmaker="build"

ARG IMAGE_SYSMAKER_ENV
WORKDIR /sysmaker/
COPY sysmaker/ misc/nginx-confd/app.conf ./

RUN echo "Image: $IMAGE_SYSMAKER_ENV" \
    && npm run sysmaker:build \
    && mv package-lock.json old-package-lock.json && mv node_modules/ old-node_modules/ \
    && find dist/apps/sysmaker \( -name '*.js' -o -name '*.css' \) -type f -exec gzip -9 -k "{}" \; \
    \
    && npm install @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs tslib \
    && cp -r node_modules/ dist/apps/api/


# ===== APP =====
FROM $IMAGE_NGINX AS sysmaker-app
LABEL maintainer="LouisSung <ls@sysmaker.org>" \
      description="Sysmaker APP" \
      sysmaker="app"

COPY --from=base /sysmaker/dist/apps/sysmaker/ /usr/share/nginx/html/
COPY --from=base /sysmaker/app.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]


# ===== API =====
FROM $IMAGE_NODE AS sysmaker-api
LABEL maintainer="LouisSung <ls@sysmaker.org>" \
      description="Sysmaker API" \
      sysmaker="api"

WORKDIR /sysmaker/api/
COPY --from=base /sysmaker/dist/apps/api/ /sysmaker/api/

ENV port=80
EXPOSE 80
CMD ["node", "/sysmaker/api/main.js"]


# ===== SINGLE =====
FROM $IMAGE_NODE AS sysmaker-single
LABEL maintainer="LouisSung <ls@sysmaker.org>" \
      description="Sysmaker" \
      sysmaker="single"

WORKDIR /sysmaker/
COPY --from=base /sysmaker/dist/apps/sysmaker/ /usr/share/nginx/html/
COPY --from=base /sysmaker/dist/apps/api/ /sysmaker/api/

RUN apk update && apk add --no-cache nginx && mkdir -p /var/run/nginx

EXPOSE 80
EXPOSE 443
ENTRYPOINT []
CMD ["sh", "-c", "nginx & nohup node /sysmaker/api/main.js"]
```

### docker-compose.yml
> `master-0012-4045ddb` ~ `now`
#### [**`.env`**](https://github.com/Sysmaker-Org/Docker/blob/master/.env)
> save as an `.env` file and put in the same folder as `docker-compose.yml`
```bash=
# Nginx for APP: Latest + Alpine (https://hub.docker.com/_/nginx?tab=tags&page=1&name=-alpine)
VER_NGINX=1.17.9-alpine
# Node.js for API: LTS !! + Alpine (https://hub.docker.com/_/node?tab=tags&page=1&name=-alpine)
VER_NODE=12.16.1-alpine3.11
# Cypress for CI and build: Sync with Node.js version !! (https://github.com/cypress-io/cypress-docker-images/tree/master/base)
VER_CYPRESS=12.16.1

IMAGE_TAG=master-0012-4045ddb
```
#### [**`sysmaker/sysmaker`**](https://github.com/Sysmaker-Org/Docker/blob/master/docker-compose.single.yml) (single)
```yaml=
# Single Sysmaker image (APP & API in single image)
version: '3.7'

# ===== configs =====
x-images:
  &images
  IMAGE_NODE: node:${VER_NODE}
  IMAGE_NGINX: nginx:${VER_NGINX}
#  IMAGE_SYSMAKER_ENV: sysmaker/sysmaker-env:${IMAGE_TAG}  # prefer using Docker Hub latest one

x-https:
  &https
  - ./misc/nginx-confd/single.https.conf:/etc/nginx/conf.d/default.conf:ro
  - ./misc/ssl/:/etc/nginx/conf.d/ssl/:ro

x-http:
  &http
  - ./misc/nginx-confd/single.http.conf:/etc/nginx/conf.d/default.conf:ro
  - ./misc/ssl/restore-ip.cloudflare:/etc/nginx/conf.d/ssl/restore-ip.cloudflare:ro


# ===== services =====
services:
  sysmaker-single:
    build:
      context: .
      target: sysmaker-single
      args: *images
    image: sysmaker/sysmaker:${IMAGE_TAG}
    container_name: Sysmaker
    hostname: Sysmaker

    volumes: *http
    ports:
      - '80:80'
      - '443:443'
```

#### [**`sysmaker/sysmaker-app`** and **`sysmaker/sysmaker-api`**](https://github.com/Sysmaker-Org/Docker/blob/master/docker-compose.yml) (normal)
```yaml=
# Normal Sysmaker images (APP + API + Nginx)
version: '3.7'

# ===== configs =====
x-images:
  &images
  IMAGE_NODE: node:${VER_NODE}
  IMAGE_NGINX: nginx:${VER_NGINX}
#  IMAGE_SYSMAKER_NPM_OR_NODE: sysmaker/sysmaker-npm:${IMAGE_TAG}  # prefer Docker Hub one

x-https:
  &https
  - ./misc/nginx-confd/normal.https.conf:/etc/nginx/conf.d/default.conf:ro
  - ./misc/ssl/:/etc/nginx/conf.d/ssl/:ro

x-http:
  &http
  - ./misc/nginx-confd/normal.http.conf:/etc/nginx/conf.d/default.conf:ro
  - ./misc/ssl/restore-ip.cloudflare:/etc/nginx/conf.d/ssl/restore-ip.cloudflare:ro

# ===== services =====
services:
  sysmaker-app:
    build:
      context: .
      target: sysmaker-app
      args: *images
    image: sysmaker/sysmaker-app:${IMAGE_TAG}
    container_name: Sysmaker-APP
    hostname: Sysmaker-APP
    networks:
      - sysmaker-lan


  sysmaker-api:
    build:
      context: .
      target: sysmaker-api
      args: *images
    image: sysmaker/sysmaker-api:${IMAGE_TAG}
    container_name: Sysmaker-API
    hostname: Sysmaker-API
    networks:
      - sysmaker-lan


  sysmaker-nginx:
    image: nginx:${VER_NGINX}
    container_name: Sysmaker-Nginx
    hostname: Sysmaker-Nginx

    volumes: *http
    ports:
      - '80:80'
      - '443:443'
    networks:
      - sysmaker-lan


networks:
  sysmaker-lan:
```

#### for [GitLab CI](https://github.com/Sysmaker-Org/Docker/blob/master/docker-compose.gitlab-ci.yml) to build images
```yaml=
# For GitLab to build production images during CI process (rarely change)
version: '3.7'

services:
  sysmaker-app:
    build:
      context: .
      target: sysmaker-app
    image: sysmaker/sysmaker-app:${IMAGE_TAG}


  sysmaker-api:
    build:
      context: .
      target: sysmaker-api
    image: sysmaker/sysmaker-api:${IMAGE_TAG}

  sysmaker-single:
    build:
      context: .
      target: sysmaker-single
    image: sysmaker/sysmaker:${IMAGE_TAG}
```

### Configs
> `master-0012-4045ddb` ~ `now`
#### [**`app.conf`**](https://github.com/Sysmaker-Org/Docker/blob/master/misc/nginx-confd/app.conf)
```clike=
server {
  listen           80;

  gzip             on;
  gzip_static      on;
  gzip_min_length  4k;
  gzip_vary        on;

  index            index.html;
  root             /usr/share/nginx/html;

  location / {
    try_files      $uri$args  $uri$args/  /index.html;
  }
}
```

#### [**`normal.http(s).conf`**](https://github.com/Sysmaker-Org/Docker/blob/master/misc/nginx-confd/normal.https.conf)
* **`https`**: *Uncomment`##`*; **`http`**: *Keep or Remove Lines*
```clike=
# Restore original ip from Cloudflare proxy
include conf.d/ssl/restore-ip.cloudflare;

# Deny requests that are not via our domains
server {
  listen                 80  default_server;
  listen                 [::]:80  default_server;
##  listen                 443  default_server;
##  listen                 [::]:443  default_server;
  server_name            _;
##  ssl_certificate        conf.d/ssl/sysmaker.crt;
##  ssl_certificate_key    conf.d/ssl/sysmaker.key;
  return                 412;
}

### Redirect to HTTPS
##server {
##  listen                 80;
##  server_name            *.sysmaker.org  localhost;
##  return                 301  https://$host$request_uri;    # redirect http:80 to https
##}

server {
##  listen                 443  ssl;
  listen                 80;
  server_name            *.sysmaker.org  localhost;

##  ssl_certificate        conf.d/ssl/sysmaker.crt;
##  ssl_certificate_key    conf.d/ssl/sysmaker.key;
##  error_page             497  https://$host$request_uri;    # redirect http:443 to https


  location ~ ^/api/v\d+/?.*$ {
    proxy_pass           http://Sysmaker-API;
  }

  location / {
    proxy_pass           http://Sysmaker-APP;
  }
}
```

#### [**`single.http(s).conf`**](https://github.com/Sysmaker-Org/Docker/blob/master/misc/nginx-confd/single.https.conf)
```clike=
# Restore original ip from Cloudflare proxy
include conf.d/ssl/restore-ip.cloudflare;

# Deny requests that are not via our domains
server {
  listen                 80  default_server;
  listen                 [::]:80  default_server;
##  listen                 443  default_server;
##  listen                 [::]:443  default_server;
  server_name            _;
##  ssl_certificate        conf.d/ssl/sysmaker.crt;
##  ssl_certificate_key    conf.d/ssl/sysmaker.key;
  return                 412;
}

### Redirect to HTTPS
##server {
##  listen                 80;
##  server_name            *.sysmaker.org  localhost;
##  return                 301  https://$host$request_uri;    # redirect http:80 to https
##}

server {
##  listen                 443  ssl;
  listen                 80;
  server_name            *.sysmaker.org  localhost;

##  ssl_certificate        conf.d/ssl/sysmaker.crt;
##  ssl_certificate_key    conf.d/ssl/sysmaker.key;
##  error_page             497  https://$host$request_uri;    # redirect http:443 to https

  access_log             /dev/stdout;
  error_log              /dev/stderr  warn;

  gzip                   on;
  gzip_static            on;
  gzip_min_length        4k;
  gzip_vary              on;

  index                  index.html;
  root                   /usr/share/nginx/html;

  location ~ ^/api/v\d+/?.*$ {
    proxy_set_header     Host  $host;
    proxy_pass           http://localhost:3000;
    proxy_redirect       off;
  }

  location / {
    try_files            $uri$args  $uri$args/  /index.html;
  }
}
```

#### [**`restore-ip.cloudflare`**](https://github.com/Sysmaker-Org/Docker/blob/master/misc/ssl/restore-ip.cloudflare)
* Required only if you're using Cloudflare proxy
```bash=
# Get IP list here: https://www.cloudflare.com/ips/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# restore original IP
real_ip_header CF-Connecting-IP;
```
