Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ REACT_APP_REPORT_WMS_LAYER=<report wms layer url>
REACT_APP_BCEID_REGISTER_URL=<URL for BCeID basic registration page>
REACT_APP_FROM_EMAIL=<default from address for outgoing emails>
REACT_APP_LEGACY_URL=<legacy URL for the old DriveBC site>
REACT_APP_MAINTENANCE_MODE=<true/false to indicate if site is in maintenance mode>

# API
DRIVEBC_INLAND_FERRY_API_BASE_URL=<inland ferry api url>
Expand Down
14 changes: 11 additions & 3 deletions compose/frontend/StaticBuild
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ FROM nginx:stable-alpine3.23

EXPOSE 3000

# Install Brotli for better compression of static assets.
# Install Brotli CLI tool for compressing static assets at build-time.
RUN apk add --no-cache brotli

# Copy pre-compiled brotli modules β€” no apk install needed, no version mismatches
Expand All @@ -68,13 +68,21 @@ RUN mkdir -p /tmp/client_temp /tmp/proxy_temp /tmp/fastcgi_temp /tmp/uwsgi_temp
RUN mkdir -p /usr/share/nginx/html
COPY --from=buildnode /app/build /usr/share/nginx/html

# --- Pre-compress Static Assets (JS, CSS, SVG) ---
RUN echo "Pre-compressing static assets with Gzip and Brotli..." && \
find /usr/share/nginx/html/static/js -name "*.js" -exec gzip -k -9 {} + && \
find /usr/share/nginx/html/static/css -name "*.css" -exec gzip -k -9 {} + && \
find /usr/share/nginx/html/static/media -name "*.svg" -exec gzip -k -9 {} + && \
find /usr/share/nginx/html/static/js -name "*.js" -exec brotli -f -k -q 11 {} + && \
find /usr/share/nginx/html/static/css -name "*.css" -exec brotli -f -k -q 11 {} + && \
find /usr/share/nginx/html/static/media -name "*.svg" -exec brotli -f -k -q 11 {} +

# Copy NGINX configuration files
COPY ./compose/frontend/default.conf /etc/nginx/conf.d/default.conf
COPY ./compose/frontend/security_headers.conf /etc/nginx/conf.d/security_headers.conf
COPY ./compose/frontend/security_headers_admin.conf /etc/nginx/conf.d/security_headers_admin.conf
COPY ./compose/frontend/blocked_ips.conf /etc/nginx/conf.d/blocked_ips.conf
COPY ./compose/frontend/legacy_redirects.conf /etc/nginx/legacy_redirects.conf
COPY ./compose/frontend/default_maintenance.txt /etc/nginx/default_maintenance.txt

# Runtime env injection hook (run by an initContainer in OpenShift)
COPY --chmod=755 ./compose/frontend/generate-config.sh /tmp/generate-config.sh
COPY --chmod=755 ./compose/frontend/generate-config.sh /tmp/generate-config.sh
59 changes: 0 additions & 59 deletions compose/frontend/default_maintenance.txt

This file was deleted.

125 changes: 57 additions & 68 deletions compose/frontend/generate-config.sh
Original file line number Diff line number Diff line change
@@ -1,79 +1,77 @@
#!/bin/sh
set -e

# This runs as an init container; outputs to shared volume for main container

# Source the vault secrets
. /vault/secrets/secrets.env

SHARED_CONFIG="/shared-config"
mkdir -p "${SHARED_CONFIG}/static"

# --- Maintenance Mode Check ---
if [ "$MAINTENANCE_MODE" = "true" ]; then
echo "Maintenance mode is enabled."
cp /etc/nginx/default_maintenance.txt "${SHARED_CONFIG}/default.conf"
exit 0
fi

# --- Copy Static Assets ---
cp -r /usr/share/nginx/html/static/. "${SHARED_CONFIG}/static/"

# --- Locate Main File ---
MAIN=$(find "${SHARED_CONFIG}/static/js" -name "main.*.js" | head -n 1)
# --- Copy Static Assets and Index ---
echo "Copying /usr/share/nginx/html/ to ${SHARED_CONFIG}..."
cp -r /usr/share/nginx/html/* "${SHARED_CONFIG}/"

# --- Create Config Snippet ---
cat > "${SHARED_CONFIG}/config_snippet.html" <<EOF
<script>
window.__ENV__ = {
BASE_MAP: '${REACT_APP_BASE_MAP}',
MAP_STYLE: '${REACT_APP_MAP_STYLE}',
API_HOST: '${REACT_APP_API_HOST}',
REPORT_WMS_LAYER: '${REACT_APP_REPORT_WMS_LAYER}',
GEOCODER_HOST: '${REACT_APP_GEOCODER_HOST}',
GEOCODER_API_CLIENT_ID: '${REACT_APP_GEOCODER_API_CLIENT_ID}',
ROUTABLE_LOCATIONS_HOST: '${REACT_APP_ROUTABLE_LOCATIONS_HOST}',
ROUTE_PLANNER: '${REACT_APP_ROUTE_PLANNER}',
ROUTE_PLANNER_CLIENT_ID: '${REACT_APP_ROUTE_PLANNER_CLIENT_ID}',
REPLAY_THE_DAY: '${REACT_APP_REPLAY_THE_DAY}',
SURVEY_LINK: '${REACT_APP_SURVEY_LINK}',
BCEID_REGISTER_URL: '${REACT_APP_BCEID_REGISTER_URL}',
FROM_EMAIL: '${REACT_APP_FROM_EMAIL}',
LEGACY_URL: '${REACT_APP_LEGACY_URL}',
RECAPTCHA_CLIENT_ID: '${REACT_APP_RECAPTCHA_CLIENT_ID}',
PRIMARY_ROUTE_GDF: '${REACT_APP_PRIMARY_ROUTE_GDF}',
PRIMARY_ROUTE_TURNCOST: '${REACT_APP_PRIMARY_ROUTE_TURNCOST}',
PRIMARY_ROUTE_XINGCOST: '${REACT_APP_PRIMARY_ROUTE_XINGCOST}',
ALTERNATE_ROUTE_GDF: '${REACT_APP_ALTERNATE_ROUTE_GDF}',
ALTERNATE_ROUTE_TURNCOST: '${REACT_APP_ALTERNATE_ROUTE_TURNCOST}',
ALTERNATE_ROUTE_XINGCOST: '${REACT_APP_ALTERNATE_ROUTE_XINGCOST}',
DEPLOYMENT_TAG: '${DEPLOYMENT_TAG}',
MAINTENANCE_MODE: '${MAINTENANCE_MODE}',
RELEASE: '${RELEASE:-}',
};
</script>
EOF

if [ -z "$MAIN" ]; then
echo "Error: Could not find main.js file to inject variables."
CONFIG_ONE_LINE=$(tr -d '\n' < "${SHARED_CONFIG}/config_snippet.html")
TARGET_INDEX="${SHARED_CONFIG}/index.html"

# --- Inject Config into HTML Safely ---
if [ -f "$TARGET_INDEX" ]; then
echo "Injecting runtime config into ${TARGET_INDEX}..."

SAFE_CONFIG=$(echo "$CONFIG_ONE_LINE" | sed 's/&/\\&/g')

sed -i "s~<head>~<head>${SAFE_CONFIG}~" "$TARGET_INDEX"
rm "${SHARED_CONFIG}/config_snippet.html"
else
echo "Error: index.html not found!"
exit 1
fi

# --- Inject Environment Variables ---
cat <<EOF >> "$MAIN"

/* Runtime Environment Variables Injected by Init Container */
window.BASE_MAP='${REACT_APP_BASE_MAP}';
window.MAP_STYLE='${REACT_APP_MAP_STYLE}';
window.API_HOST='${REACT_APP_API_HOST}';
window.REPORT_WMS_LAYER='${REACT_APP_REPORT_WMS_LAYER}';
window.GEOCODER_HOST='${REACT_APP_GEOCODER_HOST}';
window.GEOCODER_API_CLIENT_ID='${REACT_APP_GEOCODER_API_CLIENT_ID}';
window.ROUTABLE_LOCATIONS_HOST='${REACT_APP_ROUTABLE_LOCATIONS_HOST}';
window.ROUTE_PLANNER='${REACT_APP_ROUTE_PLANNER}';
window.ROUTE_PLANNER_CLIENT_ID='${REACT_APP_ROUTE_PLANNER_CLIENT_ID}';
window.REPLAY_THE_DAY='${REACT_APP_REPLAY_THE_DAY}';
window.SURVEY_LINK='${REACT_APP_SURVEY_LINK}';
window.BCEID_REGISTER_URL='${REACT_APP_BCEID_REGISTER_URL}';
window.FROM_EMAIL='${REACT_APP_FROM_EMAIL}';
window.LEGACY_URL='${REACT_APP_LEGACY_URL}';
window.RECAPTCHA_CLIENT_ID='${REACT_APP_RECAPTCHA_CLIENT_ID}';
window.ALTERNATE_ROUTE_GDF='${REACT_APP_ALTERNATE_ROUTE_GDF}';
window.ALTERNATE_ROUTE_TURNCOST='${REACT_APP_ALTERNATE_ROUTE_TURNCOST}';
window.ALTERNATE_ROUTE_XINGCOST='${REACT_APP_ALTERNATE_ROUTE_XINGCOST}';
window.DEPLOYMENT_TAG='${DEPLOYMENT_TAG}';
window.RELEASE='${RELEASE:-}';
EOF

# --- Nginx Configuration ---
# --- Nginx Configuration Routing & Rules ---
cp /etc/nginx/conf.d/default.conf "${SHARED_CONFIG}/default.conf"
cp /etc/nginx/conf.d/security_headers.conf "${SHARED_CONFIG}/security_headers.conf"

# -- Replace {ENVIRONMENT} placeholder ---
sed -i "s~{ENVIRONMENT}~$ENVIRONMENT~g" "${SHARED_CONFIG}/default.conf"

# --- Handle Robots Tag ---
if [ "$ENVIRONMENT" = "prod-drivebc" ]; then
echo "Environment is 'prod'; removing X-Robots-Tag noindex header."
sed -i '/add_header X-Robots-Tag "noindex";/d' "${SHARED_CONFIG}/security_headers.conf"
else
echo "Environment is not 'prod'; keeping X-Robots-Tag noindex header."
fi

# --- Handle Debug Route ---
if [ "$ENVIRONMENT" = "dev-drivebc" ]; then
echo "Environment is 'dev'; Adding the debug toolbar route."
sed -i 's/healthcheck)/healthcheck|__debug__)/' "${SHARED_CONFIG}/default.conf"
else
echo "Environment is not 'dev'; not adding the debug toolbar route."
fi

# Create blocked IPs configuration file
Expand All @@ -83,29 +81,20 @@ if [ -n "$BLOCKED_IPS" ]; then
echo "Processing blocked IPs..."
for ip in $(echo "$BLOCKED_IPS" | tr ';' ' '); do
CLEAN_IP=$(echo "$ip" | tr -d ' ')
if [ -n "$CLEAN_IP" ]; then
if [ -n "$CLEAN_IP" ]; then
echo "deny $CLEAN_IP;" >> "$BLOCKED_CONF"
fi
done
echo "Blocked IPs configuration created."
fi

# --- GzipPre-compression ---
echo "Gzip Compressing static assets..."
find "${SHARED_CONFIG}/static/js" -name "*.js" -exec gzip -k -9 {} +
find "${SHARED_CONFIG}/static/css" -name "main.*.css" -exec gzip -k -9 {} +
find "${SHARED_CONFIG}/static/media" -name "*.svg" -exec gzip -k -9 {} +
# --- Re-compress runtime-modified index.html ---
echo "Compressing dynamically updated index.html..."
rm -f "${TARGET_INDEX}.gz" "${TARGET_INDEX}.br"

gzip -k -9 "$TARGET_INDEX"

# --- Brotli Pre-compression ---
if command -v brotli > /dev/null; then
echo "Brotli compressing static assets..."
find "${SHARED_CONFIG}/static/js" -name "*.js" -exec brotli -f -k -q 11 {} +
find "${SHARED_CONFIG}/static/css" -name "main.*.css" -exec brotli -f -k -q 11 {} +
find "${SHARED_CONFIG}/static/media" -name "*.svg" -exec brotli -f -k -q 11 {} +
else
echo "Warning: brotli command not found in init container. Assets will only have Gzip."
brotli -f -k -q 11 "$TARGET_INDEX"
fi


echo "Configuration and assets ready in ${SHARED_CONFIG}:"
ls -la "${SHARED_CONFIG}/"
echo "Done! Configuration and pre-compressed assets ready."
Binary file modified infrastructure/main/charts/redis-0.1.0.tgz
Binary file not shown.
Binary file modified infrastructure/main/charts/static-0.1.0.tgz
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ spec:
- name: log-storage
mountPath: /logs
- name: shared-config
mountPath: /usr/share/nginx/html/static
subPath: static
mountPath: /usr/share/nginx/html
readOnly: true
- name: shared-config
mountPath: /etc/nginx/conf.d/default.conf
Expand Down
Binary file modified infrastructure/main/charts/tasks-0.1.0.tgz
Binary file not shown.
Loading
Loading