diff --git a/Dockerfile.nginx b/Dockerfile.nginx new file mode 100644 index 0000000..3e315e6 --- /dev/null +++ b/Dockerfile.nginx @@ -0,0 +1,25 @@ +FROM node:18-alpine as build + +WORKDIR /client + +COPY ./client/package*.json ./ + +RUN yarn install + +COPY ./client . + +ARG DOMAIN + +RUN yarn build + +FROM nginx:alpine + +COPY --from=build ./client/build /usr/share/nginx/html + +COPY ./ssl/* /etc/nginx/ + +COPY nginx.conf.template /etc/nginx/nginx.conf.template + +EXPOSE 80 443 + +CMD envsubst '$DOMAIN' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && nginx -g 'daemon off;' \ No newline at end of file diff --git a/Dockerfile.server b/Dockerfile.server new file mode 100644 index 0000000..0b7a0ca --- /dev/null +++ b/Dockerfile.server @@ -0,0 +1,13 @@ +FROM node:18-alpine + +WORKDIR /server + +COPY ./server/package*.json ./ + +RUN yarn install + +COPY ./server . + +EXPOSE 8000 + +CMD ["node", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..078c6a0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +version: '3.8' + +services: + server: + build: + context: . + dockerfile: Dockerfile.server + restart: always + logging: + driver: json-file + options: + max-size: "20m" + max-file: "10" + environment: + - LISTEN=0.0.0.0 + - LOG_LEVEL=${LOG_LEVEL} + - TZ=Asia/Shanghai + + nginx: + build: + context: . + dockerfile: Dockerfile.nginx + args: + DOMAIN: "ormonitor.darwinia.network" + restart: always + logging: + driver: json-file + options: + max-size: "20m" + max-file: "3" + environment: + - TZ=Asia/Shanghai + ports: + - "443:443" + - "80:80" + depends_on: + - server diff --git a/nginx.conf.template b/nginx.conf.template new file mode 100644 index 0000000..47c6304 --- /dev/null +++ b/nginx.conf.template @@ -0,0 +1,85 @@ +events { } + +http { + include mime.types; + default_type application/octet-stream; + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + gzip_buffers 16 8k; + gzip_min_length 5k; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + sendfile on; + keepalive_timeout 65; + + limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; + + upstream backend { + server server:8000; + # server server:8000 max_fails=3 fail_timeout=10s; + # server server-bk:8000 backup; + } + + server { + listen 80; + server_name ${DOMAIN}; + + return 301 https://$host$request_uri; + } + + server { + listen 443 ssl; + server_name ${DOMAIN}; + + ssl_certificate /etc/nginx/${DOMAIN}.pem; + ssl_certificate_key /etc/nginx/${DOMAIN}.key; + + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + + ssl_prefer_server_ciphers on; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri $uri/ /index.html; + } + + location /static/ { + expires 5d; + add_header Cache-Control "public, no-transform"; + alias /usr/share/nginx/html/static/; + } + + location /api { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + + limit_req zone=mylimit burst=20 nodelay; + + proxy_pass http://backend/api; + + add_header 'Access-Control-Allow-Origin' '${DOMAIN}'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + } + } +}