chore(frontend): use bitnami/openresty as base image for frontend Dockerfile (#1335)
* chore(frontend): use bitnami/openresty as base image for frontend Dockerfile openresty/openresty was not being patched as frequently as we would like, resulting in numerous vulnerabilities without resolution. bitnami/openresty is being patched more frequently. Some additional changes were necessary when porting our frontend between these distributions: - html files are in /app - nginx.conf is in /opt/bitnami/openresty/nginx/conf/nginx.conf - envsubst is not available by default in bitnami/openresty and needs to be copied in - Nginx.conf - we wrap the server block in http block and overwrite root nginx.conf - using the existing bitnami/openresty nginx.conf as a server block alone causes issues with bitnami/openresty, as bitnami/openresty provides a root nginx.conf which conflicts with directives in Speckle's server block - we copy the directives from openresty/openresty (which are known to work with Speckle's server block), and apply them alongside Speckle's server block. This creates a new root nginx.conf which we can overwrite the default on the image. - nginx should use a port available to non sudo/root user, we have selected 8080 instead of previous 80 - need to explicitly output nginx logs to stderr / stdout Created a readonly root file system on Kubernetes. This requires the following changes: - emptyDir volumes are mounted in kubernetes to allow bitnami/openresty to write to specific locations - explicitly include and copy mime.types file to nginx configuration directory Due to the change to non-privileged port number (8080), the following subsequent changes were required: - Update 1-click deployment script to match frontend at port 8080 - Updates docker-compose-speckle.yaml file Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
This commit is contained in:
Родитель
7f617f132e
Коммит
68fd86b754
|
@ -7,7 +7,7 @@ services:
|
|||
image: speckle/speckle-frontend:local
|
||||
restart: always
|
||||
ports:
|
||||
- '0.0.0.0:80:80'
|
||||
- '0.0.0.0:80:8080'
|
||||
environment:
|
||||
FILE_SIZE_LIMIT_MB: 100
|
||||
|
||||
|
|
|
@ -30,21 +30,29 @@ COPY packages/shared ./packages/shared/
|
|||
# This way the foreach only builds the frontend and its deps
|
||||
RUN yarn workspaces foreach run build
|
||||
|
||||
RUN DEBIAN_FRONTEND=noninteractive \
|
||||
apt-get -q update && \
|
||||
apt-get install --no-install-recommends -y \
|
||||
gettext=0.21-4 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# production stage
|
||||
FROM openresty/openresty:1.21.4.1-4-jammy-amd64 as production-stage
|
||||
FROM bitnami/openresty:1.21.4-1-debian-11-r80 as production-stage
|
||||
ARG NODE_ENV
|
||||
ARG SPECKLE_SERVER_VERSION
|
||||
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
ENV FILE_SIZE_LIMIT_MB=100
|
||||
|
||||
COPY --from=build-stage /speckle-server/packages/frontend/dist /usr/share/nginx/html
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build-stage /usr/bin/envsubst /usr/bin/envsubst
|
||||
|
||||
COPY packages/frontend/nginx/ /etc/nginx/
|
||||
COPY --from=build-stage /speckle-server/packages/frontend/dist /app
|
||||
|
||||
COPY packages/frontend/nginx/ /opt/bitnami/openresty/nginx/
|
||||
|
||||
# prepare the environment
|
||||
ENTRYPOINT ["/etc/nginx/docker-entrypoint.sh"]
|
||||
ENTRYPOINT ["/opt/bitnami/openresty/nginx/docker-entrypoint.sh"]
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
EXPOSE 8080
|
||||
CMD ["/opt/bitnami/scripts/openresty/entrypoint.sh", "/opt/bitnami/scripts/openresty/run.sh"]
|
||||
|
|
|
@ -5,7 +5,8 @@ defined_envs=$(printf '${%s} ' $(env | cut -d= -f1))
|
|||
|
||||
echo Starting nginx environment template rendering with "${defined_envs}"
|
||||
|
||||
envsubst "${defined_envs}" < /etc/nginx/templates/nginx.conf.template > /etc/nginx/conf.d/nginx.conf
|
||||
cp /opt/bitnami/openresty/nginx/mime.types /opt/bitnami/openresty/nginx/conf/mime.types
|
||||
envsubst "${defined_envs}" < /opt/bitnami/openresty/nginx/templates/nginx.conf.template > /opt/bitnami/openresty/nginx/conf/nginx.conf
|
||||
|
||||
echo Nginx conf rendered, starting server...
|
||||
exec "$@"
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/avif avif;
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/wasm wasm;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
|
@ -1,130 +1,147 @@
|
|||
server_tokens off;
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
pcre_jit on;
|
||||
error_log stderr info;
|
||||
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_min_length 256;
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/geo+json
|
||||
application/javascript
|
||||
application/x-javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/manifest+json
|
||||
application/rdf+xml
|
||||
application/rss+xml
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/eot
|
||||
font/otf
|
||||
font/ttf
|
||||
image/svg+xml
|
||||
text/css
|
||||
text/javascript
|
||||
text/plain
|
||||
text/xml;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
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 104.16.0.0/13;
|
||||
set_real_ip_from 104.24.0.0/14;
|
||||
set_real_ip_from 108.162.192.0/18;
|
||||
set_real_ip_from 131.0.72.0/22;
|
||||
set_real_ip_from 141.101.64.0/18;
|
||||
set_real_ip_from 162.158.0.0/15;
|
||||
set_real_ip_from 172.64.0.0/13;
|
||||
set_real_ip_from 173.245.48.0/20;
|
||||
set_real_ip_from 188.114.96.0/20;
|
||||
set_real_ip_from 190.93.240.0/20;
|
||||
set_real_ip_from 197.234.240.0/22;
|
||||
set_real_ip_from 198.41.128.0/17;
|
||||
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 2c0f:f248::/32;
|
||||
set_real_ip_from 2a06:98c0::/29;
|
||||
|
||||
#use any of the following two
|
||||
real_ip_header CF-Connecting-IP;
|
||||
#real_ip_header X-Forwarded-For;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
client_max_body_size 100m;
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# move default write paths to a custom directory
|
||||
# kubernetes can mount this directory and prevent writes to the root directory
|
||||
# https://github.com/openresty/docker-openresty/issues/119
|
||||
client_body_temp_path /var/run/openresty/nginx-client-body;
|
||||
proxy_temp_path /var/run/openresty/nginx-proxy;
|
||||
fastcgi_temp_path /var/run/openresty/nginx-fastcgi;
|
||||
uwsgi_temp_path /var/run/openresty/nginx-uwsgi;
|
||||
scgi_temp_path /var/run/openresty/nginx-scgi;
|
||||
client_body_temp_path /bitnami/openresty/nginx-client-body;
|
||||
proxy_temp_path /bitnami/openresty/nginx-proxy;
|
||||
fastcgi_temp_path /bitnami/openresty/nginx-fastcgi;
|
||||
uwsgi_temp_path /bitnami/openresty/nginx-uwsgi;
|
||||
scgi_temp_path /bitnami/openresty/nginx-scgi;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
access_log /dev/stdout;
|
||||
|
||||
location ~* ^/(favicon.ico|logo.svg|loadingImage.png|og_image.png) {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
expires 1d;
|
||||
}
|
||||
# Speckle configuration
|
||||
server_tokens off;
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
|
||||
location ~* ^/(js/.*|fonts/.*|(css/.*)|(img/.*)|(assets/.*)) {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
expires 1y;
|
||||
}
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_min_length 256;
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/geo+json
|
||||
application/javascript
|
||||
application/x-javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/manifest+json
|
||||
application/rdf+xml
|
||||
application/rss+xml
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/eot
|
||||
font/otf
|
||||
font/ttf
|
||||
image/svg+xml
|
||||
text/css
|
||||
text/javascript
|
||||
text/plain
|
||||
text/xml;
|
||||
|
||||
location ~ ^/streams/.* {
|
||||
default_type text/html;
|
||||
content_by_lua_block {
|
||||
local f = assert(io.open('/usr/share/nginx/html/index.html', "rb"))
|
||||
local content = f:read("*all")
|
||||
f:close()
|
||||
local http_host = ngx.var.http_host
|
||||
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 104.16.0.0/13;
|
||||
set_real_ip_from 104.24.0.0/14;
|
||||
set_real_ip_from 108.162.192.0/18;
|
||||
set_real_ip_from 131.0.72.0/22;
|
||||
set_real_ip_from 141.101.64.0/18;
|
||||
set_real_ip_from 162.158.0.0/15;
|
||||
set_real_ip_from 172.64.0.0/13;
|
||||
set_real_ip_from 173.245.48.0/20;
|
||||
set_real_ip_from 188.114.96.0/20;
|
||||
set_real_ip_from 190.93.240.0/20;
|
||||
set_real_ip_from 197.234.240.0/22;
|
||||
set_real_ip_from 198.41.128.0/17;
|
||||
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 2c0f:f248::/32;
|
||||
set_real_ip_from 2a06:98c0::/29;
|
||||
|
||||
content = content:gsub('<meta property=og:title (.-)>', '<meta property=og:title content="Speckle Stream">')
|
||||
#use any of the following two
|
||||
real_ip_header CF-Connecting-IP;
|
||||
#real_ip_header X-Forwarded-For;
|
||||
|
||||
local stream_id = ngx.var.uri:sub(10)
|
||||
local img_tag = '<meta property=og:image content="https://' .. http_host .. '/preview/' .. stream_id .. '?postprocess=og&ts=' .. ngx.now() .. '">'
|
||||
server {
|
||||
listen 8080;
|
||||
client_max_body_size 100m;
|
||||
|
||||
content = content:gsub('<meta property=og:image (.-)>', img_tag)
|
||||
location / {
|
||||
root /app;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
ngx.say(content)
|
||||
location ~* ^/(favicon.ico|logo.svg|loadingImage.png|og_image.png) {
|
||||
root /app;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
expires 1d;
|
||||
}
|
||||
|
||||
location ~* ^/(js/.*|fonts/.*|(css/.*)|(img/.*)|(assets/.*)) {
|
||||
root /app;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
location ~ ^/streams/.* {
|
||||
default_type text/html;
|
||||
content_by_lua_block {
|
||||
local f = assert(io.open('/app/index.html', "rb"))
|
||||
local content = f:read("*all")
|
||||
f:close()
|
||||
local http_host = ngx.var.http_host
|
||||
|
||||
content = content:gsub('<meta property=og:title (.-)>', '<meta property=og:title content="Speckle Stream">')
|
||||
|
||||
local stream_id = ngx.var.uri:sub(10)
|
||||
local img_tag = '<meta property=og:image content="https://' .. http_host .. '/preview/' .. stream_id .. '?postprocess=og&ts=' .. ngx.now() .. '">'
|
||||
|
||||
content = content:gsub('<meta property=og:image (.-)>', img_tag)
|
||||
|
||||
ngx.say(content)
|
||||
}
|
||||
}
|
||||
|
||||
location ~* ^/(graphql|explorer|(auth/.*)|(objects/.*)|(preview/.*)|(api/.*)|(static/.*)) {
|
||||
resolver 127.0.0.11 valid=30s;
|
||||
set $upstream_speckle_server speckle-server;
|
||||
client_max_body_size ${FILE_SIZE_LIMIT_MB}m;
|
||||
proxy_pass http://$upstream_speckle_server:3000;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
location = /50x.html {
|
||||
root /app;
|
||||
}
|
||||
}
|
||||
|
||||
location ~* ^/(graphql|explorer|(auth/.*)|(objects/.*)|(preview/.*)|(api/.*)|(static/.*)) {
|
||||
resolver 127.0.0.11 valid=30s;
|
||||
set $upstream_speckle_server speckle-server;
|
||||
client_max_body_size ${FILE_SIZE_LIMIT_MB}m;
|
||||
proxy_pass http://$upstream_speckle_server:3000;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ services:
|
|||
image: speckle/speckle-frontend:2
|
||||
restart: always
|
||||
ports:
|
||||
- '127.0.0.1:8000:80'
|
||||
- '127.0.0.1:8080:8080'
|
||||
environment:
|
||||
FILE_SIZE_LIMIT_MB: 100
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ server {
|
|||
client_max_body_size 100m;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_pass http://localhost:8080;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
|
|
|
@ -25,7 +25,7 @@ spec:
|
|||
|
||||
ports:
|
||||
- name: www
|
||||
containerPort: 80
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
|
||||
resources:
|
||||
|
@ -53,6 +53,24 @@ spec:
|
|||
- name: FILE_SIZE_LIMIT_MB
|
||||
value: {{ .Values.file_size_limit_mb | quote }}
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 20000
|
||||
|
||||
volumeMounts:
|
||||
- name: openresty-temp
|
||||
mountPath: /bitnami/openresty
|
||||
- name: openresty-conf
|
||||
mountPath: /opt/bitnami/openresty/nginx/conf/
|
||||
- name: openresty-logs
|
||||
mountPath: /opt/bitnami/openresty/nginx/logs/
|
||||
|
||||
priorityClassName: high-priority
|
||||
{{- if .Values.frontend.affinity }}
|
||||
affinity: {{- include "speckle.renderTpl" (dict "value" .Values.frontend.affinity "context" $) | nindent 8 }}
|
||||
|
@ -69,3 +87,11 @@ spec:
|
|||
{{- if .Values.frontend.serviceAccount.create }}
|
||||
serviceAccountName: {{ include "frontend.name" $ }}
|
||||
{{- end }}
|
||||
|
||||
volumes:
|
||||
- name: openresty-temp
|
||||
emptyDir: {}
|
||||
- name: openresty-conf
|
||||
emptyDir: {}
|
||||
- name: openresty-logs
|
||||
emptyDir: {}
|
||||
|
|
|
@ -12,5 +12,5 @@ spec:
|
|||
ports:
|
||||
- protocol: TCP
|
||||
name: www
|
||||
port: 80
|
||||
port: 8080
|
||||
targetPort: www
|
||||
|
|
|
@ -30,7 +30,7 @@ spec:
|
|||
service:
|
||||
name: speckle-frontend
|
||||
port:
|
||||
number: 80
|
||||
number: 8080
|
||||
- pathType: Exact
|
||||
path: "/(graphql|explorer|(auth/.*)|(objects/.*)|(preview/.*)|(api/.*)|(static/.*))"
|
||||
backend:
|
||||
|
|
Загрузка…
Ссылка в новой задаче