mirror of
https://github.com/frappe/frappe_docker.git
synced 2025-01-10 09:02:13 +00:00
Update frappe-nginx, erpnext-nginx
This commit is contained in:
parent
b0b176c144
commit
b62b3758a7
@ -1,75 +1,83 @@
|
|||||||
# This image uses nvm and same base image as the worker image.
|
# TODO: Add errorpages
|
||||||
# This is done to ensures that node-sass binary remains common.
|
FROM node:14-bullseye-slim as base
|
||||||
# node-sass is required to enable website theme feature used
|
|
||||||
# by Website Manager role in Frappe Framework
|
|
||||||
ARG PYTHON_VERSION=3.9
|
|
||||||
FROM python:${PYTHON_VERSION}-slim-bullseye as builder
|
|
||||||
|
|
||||||
ARG GIT_REPO=https://github.com/frappe/frappe
|
|
||||||
ARG GIT_BRANCH=develop
|
|
||||||
|
|
||||||
ENV NODE_VERSION=14.18.1
|
|
||||||
ENV NVM_DIR=/root/.nvm
|
|
||||||
ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
|
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends -y \
|
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
git \
|
git \
|
||||||
build-essential \
|
build-essential \
|
||||||
wget \
|
python \
|
||||||
# python2 for version-12 builds
|
ca-certificates \
|
||||||
python2 \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install nvm with node and yarn
|
WORKDIR /root/frappe-bench
|
||||||
RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \
|
RUN mkdir -p apps sites/assets/frappe
|
||||||
&& . ${NVM_DIR}/nvm.sh \
|
|
||||||
&& nvm install ${NODE_VERSION} \
|
|
||||||
&& npm install -g yarn \
|
|
||||||
&& rm -rf ${NVM_DIR}/.cache
|
|
||||||
|
|
||||||
WORKDIR /home/frappe/frappe-bench
|
ARG FRAPPE_VERSION
|
||||||
|
RUN git clone --depth 1 -b ${FRAPPE_VERSION} https://github.com/frappe/frappe apps/frappe \
|
||||||
|
&& echo "frappe" >sites/apps.txt
|
||||||
|
|
||||||
RUN mkdir -p apps sites/assets/css sites/assets/frappe /var/www/error_pages
|
WORKDIR /root/frappe-bench/apps/frappe
|
||||||
RUN echo "frappe" > sites/apps.txt
|
|
||||||
|
|
||||||
RUN git clone --depth 1 -b ${GIT_BRANCH} ${GIT_REPO} apps/frappe
|
|
||||||
RUN cd apps/frappe \
|
|
||||||
&& yarn \
|
|
||||||
&& yarn run production \
|
|
||||||
&& yarn install --production=true
|
|
||||||
|
|
||||||
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
|
FROM base as frappe_node_modules
|
||||||
&& cp -r /tmp/bench/bench/config/templates /var/www/error_pages
|
|
||||||
|
|
||||||
RUN cp -R apps/frappe/frappe/public/* sites/assets/frappe \
|
RUN yarn --prod
|
||||||
&& cp -R apps/frappe/node_modules sites/assets/frappe/
|
|
||||||
|
|
||||||
FROM nginxinc/nginx-unprivileged:latest
|
|
||||||
|
|
||||||
USER root
|
FROM frappe_node_modules as frappe_assets
|
||||||
|
|
||||||
RUN usermod -u 1000 nginx && groupmod -g 1000 nginx
|
RUN if [ "$(uname -m)" = "aarch64" ]; then \
|
||||||
|
yarn remove svg-sprite \
|
||||||
|
&& yarn add sass; \
|
||||||
|
fi \
|
||||||
|
&& yarn
|
||||||
|
|
||||||
COPY --from=builder --chown=1000:1000 /home/frappe/frappe-bench/sites /var/www/html/
|
RUN yarn run production \
|
||||||
COPY --from=builder --chown=1000:1000 /var/www/error_pages /var/www/
|
&& cp -R frappe/public/* ../../sites/assets/frappe \
|
||||||
COPY build/frappe-nginx/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
|
&& rm ../../sites/apps.txt
|
||||||
COPY build/frappe-nginx/docker-entrypoint.sh /
|
|
||||||
|
|
||||||
RUN apt-get update \
|
# Get rid of development node modules
|
||||||
&& apt-get install --no-install-recommends -y \
|
COPY --from=frappe_node_modules /root/frappe-bench/apps/frappe/node_modules /root/frappe-bench/sites/assets/frappe/
|
||||||
rsync \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN echo "#!/bin/bash" > /rsync \
|
|
||||||
&& chmod +x /rsync
|
|
||||||
|
|
||||||
RUN mkdir /assets
|
FROM nginx:1.21-alpine as frappe
|
||||||
VOLUME [ "/assets" ]
|
|
||||||
|
|
||||||
RUN chown -R nginx:nginx /assets /etc/nginx/conf.d/ /var/www/html/
|
COPY --from=frappe_assets /root/frappe-bench/sites /usr/share/nginx/html
|
||||||
|
COPY nginx-template.conf /
|
||||||
|
|
||||||
USER nginx
|
CMD [ "/bin/sh" , "-c" , "envsubst '${BACKEND} ${SOCKETIO} ${FRAPPE_SITE_NAME_HEADER}' </nginx-template.conf >/etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'" ]
|
||||||
|
|
||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
# Next stages are relevant to ERPNext.
|
||||||
|
# Builds are much more efficient if we reuse Frappe assets and Node modules.
|
||||||
|
|
||||||
|
FROM base as erpnext_node_modules
|
||||||
|
|
||||||
|
ARG ERPNEXT_VERSION
|
||||||
|
RUN cd ../.. \
|
||||||
|
&& git clone --depth 1 -b ${ERPNEXT_VERSION} https://github.com/frappe/erpnext apps/erpnext \
|
||||||
|
&& echo "frappe\nerpnext" >sites/apps.txt
|
||||||
|
|
||||||
|
RUN yarn --cwd ../erpnext --prod
|
||||||
|
|
||||||
|
|
||||||
|
FROM erpnext_node_modules as erpnext_assets
|
||||||
|
|
||||||
|
# Reuse development node_modules from frappe_assets
|
||||||
|
COPY --from=frappe_assets /root/frappe-bench/apps/frappe/node_modules /root/frappe-bench/apps/frappe/node_modules
|
||||||
|
COPY --from=frappe_assets /root/frappe-bench/apps/frappe/package.json /root/frappe-bench/apps/frappe/yarn.lock /root/frappe-bench/apps/frappe/
|
||||||
|
|
||||||
|
RUN mkdir -p ../../sites/assets/erpnext
|
||||||
|
RUN yarn --cwd ../erpnext
|
||||||
|
|
||||||
|
RUN yarn run production --app erpnext \
|
||||||
|
&& cp -R ../erpnext/erpnext/public/* ../../sites/assets/erpnext \
|
||||||
|
&& rm ../../sites/apps.txt
|
||||||
|
|
||||||
|
# Get rid of development node modules
|
||||||
|
COPY --from=erpnext_node_modules /root/frappe-bench/apps/erpnext/node_modules /root/frappe-bench/apps/erpnext/node_modules
|
||||||
|
|
||||||
|
|
||||||
|
FROM frappe as erpnext
|
||||||
|
|
||||||
|
COPY --from=erpnext_assets /root/frappe-bench/sites /usr/share/nginx/html
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
#!/bin/bash -ae
|
|
||||||
|
|
||||||
## Thanks
|
|
||||||
# https://serverfault.com/a/919212
|
|
||||||
##
|
|
||||||
|
|
||||||
rsync -a --delete /var/www/html/assets/* /assets
|
|
||||||
|
|
||||||
/rsync
|
|
||||||
|
|
||||||
# shellcheck disable=SC2012
|
|
||||||
touch /var/www/html/sites/.build -r "$(ls -td /assets/* | head -n 1)"
|
|
||||||
|
|
||||||
[[ -z "${FRAPPE_PY}" ]] && FRAPPE_PY='0.0.0.0'
|
|
||||||
|
|
||||||
[[ -z "${FRAPPE_PY_PORT}" ]] && FRAPPE_PY_PORT='8000'
|
|
||||||
|
|
||||||
[[ -z "${FRAPPE_SOCKETIO}" ]] && FRAPPE_SOCKETIO='0.0.0.0'
|
|
||||||
|
|
||||||
[[ -z "${SOCKETIO_PORT}" ]] && SOCKETIO_PORT='9000'
|
|
||||||
|
|
||||||
[[ -z "${HTTP_TIMEOUT}" ]] && HTTP_TIMEOUT='120'
|
|
||||||
|
|
||||||
[[ -z "${UPSTREAM_REAL_IP_ADDRESS}" ]] && UPSTREAM_REAL_IP_ADDRESS='127.0.0.1'
|
|
||||||
|
|
||||||
[[ -z "${UPSTREAM_REAL_IP_RECURSIVE}" ]] && UPSTREAM_REAL_IP_RECURSIVE='off'
|
|
||||||
|
|
||||||
[[ -z "${UPSTREAM_REAL_IP_HEADER}" ]] && UPSTREAM_REAL_IP_HEADER='X-Forwarded-For'
|
|
||||||
|
|
||||||
[[ -z "${FRAPPE_SITE_NAME_HEADER}" ]] && FRAPPE_SITE_NAME_HEADER="\$host"
|
|
||||||
|
|
||||||
[[ -z "${HTTP_HOST}" ]] && HTTP_HOST="\$http_host"
|
|
||||||
|
|
||||||
[[ -z "${WEB_PORT}" ]] && WEB_PORT="8080"
|
|
||||||
|
|
||||||
[[ -z "${SKIP_NGINX_TEMPLATE_GENERATION}" ]] && SKIP_NGINX_TEMPLATE_GENERATION='0'
|
|
||||||
|
|
||||||
if [[ ${SKIP_NGINX_TEMPLATE_GENERATION} == 1 ]]; then
|
|
||||||
echo "Skipping default NGINX template generation. Please mount your own NGINX config file inside /etc/nginx/conf.d"
|
|
||||||
else
|
|
||||||
echo "Generating default template"
|
|
||||||
# shellcheck disable=SC2016
|
|
||||||
envsubst '${FRAPPE_PY}
|
|
||||||
${FRAPPE_PY_PORT}
|
|
||||||
${FRAPPE_SOCKETIO}
|
|
||||||
${SOCKETIO_PORT}
|
|
||||||
${HTTP_TIMEOUT}
|
|
||||||
${UPSTREAM_REAL_IP_ADDRESS}
|
|
||||||
${UPSTREAM_REAL_IP_RECURSIVE}
|
|
||||||
${FRAPPE_SITE_NAME_HEADER}
|
|
||||||
${HTTP_HOST}
|
|
||||||
${UPSTREAM_REAL_IP_HEADER}
|
|
||||||
${WEB_PORT}' \
|
|
||||||
</etc/nginx/conf.d/default.conf.template >/etc/nginx/conf.d/default.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Waiting for frappe-python to be available on ${FRAPPE_PY} port ${FRAPPE_PY_PORT}"
|
|
||||||
# shellcheck disable=SC2016
|
|
||||||
timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' ${FRAPPE_PY} ${FRAPPE_PY_PORT}
|
|
||||||
echo "Frappe-python available on ${FRAPPE_PY} port ${FRAPPE_PY_PORT}"
|
|
||||||
echo "Waiting for frappe-socketio to be available on ${FRAPPE_SOCKETIO} port ${SOCKETIO_PORT}"
|
|
||||||
# shellcheck disable=SC2016
|
|
||||||
timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' ${FRAPPE_SOCKETIO} ${SOCKETIO_PORT}
|
|
||||||
echo "Frappe-socketio available on ${FRAPPE_SOCKETIO} port ${SOCKETIO_PORT}"
|
|
||||||
|
|
||||||
exec "$@"
|
|
@ -1,118 +0,0 @@
|
|||||||
upstream frappe-server {
|
|
||||||
server ${FRAPPE_PY}:${FRAPPE_PY_PORT} fail_timeout=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
upstream socketio-server {
|
|
||||||
server ${FRAPPE_SOCKETIO}:${SOCKETIO_PORT} fail_timeout=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Parse the X-Forwarded-Proto header - if set - defaulting to $scheme.
|
|
||||||
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
|
|
||||||
default $scheme;
|
|
||||||
https https;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen ${WEB_PORT};
|
|
||||||
server_name $http_host;
|
|
||||||
root /var/www/html;
|
|
||||||
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN";
|
|
||||||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
|
||||||
|
|
||||||
# Define ${UPSTREAM_REAL_IP_ADDRESS} as our trusted upstream address, so we will be using
|
|
||||||
# its ${UPSTREAM_REAL_IP_HEADER} address as our remote address
|
|
||||||
set_real_ip_from ${UPSTREAM_REAL_IP_ADDRESS};
|
|
||||||
real_ip_header ${UPSTREAM_REAL_IP_HEADER};
|
|
||||||
real_ip_recursive ${UPSTREAM_REAL_IP_RECURSIVE};
|
|
||||||
|
|
||||||
location /assets {
|
|
||||||
try_files $uri =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/protected/(.*) {
|
|
||||||
internal;
|
|
||||||
try_files /sites/$http_host/$1 =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /socket.io {
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Origin $proxy_x_forwarded_proto://$http_host;
|
|
||||||
proxy_set_header X-Frappe-Site-Name ${FRAPPE_SITE_NAME_HEADER};
|
|
||||||
proxy_set_header Host ${HTTP_HOST};
|
|
||||||
|
|
||||||
proxy_pass http://socketio-server;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
rewrite ^(.+)/$ $1 permanent;
|
|
||||||
rewrite ^(.+)/index\.html$ $1 permanent;
|
|
||||||
rewrite ^(.+)\.html$ $1 permanent;
|
|
||||||
|
|
||||||
location ~ ^/files/.*.(htm|html|svg|xml) {
|
|
||||||
add_header Content-disposition "attachment";
|
|
||||||
try_files /sites/$http_host/public/$uri @webserver;
|
|
||||||
}
|
|
||||||
|
|
||||||
try_files /sites/$http_host/public/$uri @webserver;
|
|
||||||
}
|
|
||||||
|
|
||||||
location @webserver {
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
|
||||||
proxy_set_header X-Frappe-Site-Name ${FRAPPE_SITE_NAME_HEADER};
|
|
||||||
proxy_set_header Host ${HTTP_HOST};
|
|
||||||
proxy_set_header X-Use-X-Accel-Redirect True;
|
|
||||||
proxy_read_timeout ${HTTP_TIMEOUT};
|
|
||||||
proxy_redirect off;
|
|
||||||
|
|
||||||
proxy_pass http://frappe-server;
|
|
||||||
}
|
|
||||||
|
|
||||||
# error pages
|
|
||||||
error_page 502 /502.html;
|
|
||||||
location /502.html {
|
|
||||||
root /var/www/templates;
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
# optimizations
|
|
||||||
sendfile on;
|
|
||||||
keepalive_timeout 15;
|
|
||||||
client_max_body_size 50m;
|
|
||||||
client_body_buffer_size 16K;
|
|
||||||
client_header_buffer_size 1k;
|
|
||||||
|
|
||||||
# enable gzip compression
|
|
||||||
# based on https://mattstauffer.co/blog/enabling-gzip-on-nginx-servers-including-laravel-forge
|
|
||||||
gzip on;
|
|
||||||
gzip_http_version 1.1;
|
|
||||||
gzip_comp_level 5;
|
|
||||||
gzip_min_length 256;
|
|
||||||
gzip_proxied any;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_types
|
|
||||||
application/atom+xml
|
|
||||||
application/javascript
|
|
||||||
application/json
|
|
||||||
application/rss+xml
|
|
||||||
application/vnd.ms-fontobject
|
|
||||||
application/x-font-ttf
|
|
||||||
application/font-woff
|
|
||||||
application/x-web-app-manifest+json
|
|
||||||
application/xhtml+xml
|
|
||||||
application/xml
|
|
||||||
font/opentype
|
|
||||||
image/svg+xml
|
|
||||||
image/x-icon
|
|
||||||
text/css
|
|
||||||
text/plain
|
|
||||||
text/x-component;
|
|
||||||
# text/html is always compressed by HttpGzipModule
|
|
||||||
}
|
|
109
build/frappe-nginx/nginx-template.conf
Normal file
109
build/frappe-nginx/nginx-template.conf
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
upstream backend-server {
|
||||||
|
server ${BACKEND} fail_timeout=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream socketio-server {
|
||||||
|
server ${SOCKETIO} fail_timeout=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name $http_host;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
proxy_buffer_size 128k;
|
||||||
|
proxy_buffers 4 256k;
|
||||||
|
proxy_busy_buffers_size 256k;
|
||||||
|
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Referrer-Policy "same-origin, strict-origin-when-cross-origin";
|
||||||
|
|
||||||
|
location /assets {
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/protected/(.*) {
|
||||||
|
internal;
|
||||||
|
try_files /sites/$http_host/$1 =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /socket.io {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header X-Frappe-Site-Name ${FRAPPE_SITE_NAME_HEADER};
|
||||||
|
proxy_set_header Origin $scheme://$http_host;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
|
||||||
|
proxy_pass http://socketio-server;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
rewrite ^(.+)/$ $1 permanent;
|
||||||
|
rewrite ^(.+)/index\.html$ $1 permanent;
|
||||||
|
rewrite ^(.+)\.html$ $1 permanent;
|
||||||
|
|
||||||
|
location ~ ^/files/.*.(htm|html|svg|xml) {
|
||||||
|
add_header Content-disposition "attachment";
|
||||||
|
try_files /sites/$http_host/public/$uri @webserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_files /sites/$http_host/public/$uri @webserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
location @webserver {
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Frappe-Site-Name ${FRAPPE_SITE_NAME_HEADER};
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Use-X-Accel-Redirect True;
|
||||||
|
proxy_read_timeout 120;
|
||||||
|
proxy_redirect off;
|
||||||
|
|
||||||
|
proxy_pass http://backend-server;
|
||||||
|
}
|
||||||
|
|
||||||
|
# error pages
|
||||||
|
error_page 502 /502.html;
|
||||||
|
location /502.html {
|
||||||
|
root /var/www/templates;
|
||||||
|
internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
# optimizations
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 15;
|
||||||
|
client_max_body_size 50m;
|
||||||
|
client_body_buffer_size 16K;
|
||||||
|
client_header_buffer_size 1k;
|
||||||
|
|
||||||
|
# enable gzip compression
|
||||||
|
# based on https://mattstauffer.co/blog/enabling-gzip-on-nginx-servers-including-laravel-forge
|
||||||
|
gzip on;
|
||||||
|
gzip_http_version 1.1;
|
||||||
|
gzip_comp_level 5;
|
||||||
|
gzip_min_length 256;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_types
|
||||||
|
application/atom+xml
|
||||||
|
application/javascript
|
||||||
|
application/json
|
||||||
|
application/rss+xml
|
||||||
|
application/vnd.ms-fontobject
|
||||||
|
application/x-font-ttf
|
||||||
|
application/font-woff
|
||||||
|
application/x-web-app-manifest+json
|
||||||
|
application/xhtml+xml
|
||||||
|
application/xml
|
||||||
|
font/opentype
|
||||||
|
image/svg+xml
|
||||||
|
image/x-icon
|
||||||
|
text/css
|
||||||
|
text/plain
|
||||||
|
text/x-component;
|
||||||
|
# text/html is always compressed by HttpGzipModule
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user