Skip to content
Open
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
18 changes: 18 additions & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Read Node.js version
id: node_version
run: echo "NODE_VER=$(cat .nvmrc)" >> $GITHUB_OUTPUT

- name: Install pnpm
uses: pnpm/action-setup@v2

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ steps.node_version.outputs.NODE_VER }}
cache: 'pnpm'

- name: Security Audit
run: pnpm audit --audit-level high

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

Expand Down Expand Up @@ -50,6 +66,8 @@ jobs:
labels: ${{ steps.meta_main.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NODE_VERSION=${{ steps.node_version.outputs.NODE_VER }}
secrets: |
"env_variables=${{ secrets.ENV_VARIABLES}}"

Expand Down
44 changes: 35 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
FROM node:20 AS builder
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine AS dependencies

WORKDIR /app

RUN corepack enable

COPY ./pnpm-lock.yaml ./package.json ./
COPY package.json pnpm-lock.yaml ./

RUN pnpm install
RUN pnpm install --frozen-lockfile --ignore-scripts

FROM node:${NODE_VERSION}-alpine AS builder

WORKDIR /app

RUN corepack enable

COPY package.json pnpm-lock.yaml ./

COPY --from=dependencies /app/node_modules ./node_modules

COPY . .

Expand All @@ -15,15 +26,30 @@ RUN --mount=type=secret,id=env_variables \

RUN pnpm ioc-generate

# Un comment if using graphql instead of REST
# RUN pnpm graphql
RUN pnpm graphql

RUN pnpm build

FROM nginx
FROM nginx:alpine

# delete default nginx static files
RUN rm -rf /usr/share/nginx/html/*
RUN apk add --no-cache dumb-init

# copy build files from builder stage
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy build files from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html

RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /etc/nginx/conf.d && \
touch /var/run/nginx.pid && \
chown -R nginx:nginx /var/run/nginx.pid

USER nginx

EXPOSE 80

ENTRYPOINT ["/usr/bin/dumb-init", "--"]

CMD ["nginx", "-g", "daemon off;"]
35 changes: 35 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;

# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}

# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}