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
36 changes: 36 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# MasterNode-App environment variables (example).
# Copy this to `.env` and keep `.env` OUT of git (see .gitignore).

# --- server ---
SERVER_HOST=0.0.0.0
SERVER_PORT=5001
BASE_URL=http://localhost:5001

# --- MongoDB ---
# Always use an authenticated URI in production. Example:
# mongodb://masternode_user:STRONG_PASSWORD@mongodb:27017/governance?authSource=admin
DB_URI=mongodb://127.0.0.1:27017/mnApp

# --- Blockchain ---
BC_RPC=https://rpc.xinfin.network
BC_WS=wss://ws.xinfin.network
BC_NETWORK_ID=50

# --- Swagger UI (production only) ---
# If either is unset, /api-docs is disabled in production.
# SWAGGER_USER=
# SWAGGER_PASS=

# --- Reverse proxy ---
# How many upstream hops to trust when reading client IPs for rate limiting.
# Fly.io / Heroku: 1. Behind two-layer proxy (e.g. CloudFlare + Nginx): 2.
# Leave unset to use the default (1). Only set 'true' if you fully trust all
# upstream hops, otherwise clients can spoof their IP via X-Forwarded-For.
# TRUST_PROXY=1

# --- Optional feature flags ---
# Default to "development" in this example so that `cp .env.example .env`
# yields a working local boot. Production deployments MUST override this
# (NODE_ENV=production, mainnet, testnet, or devnet) to enable HSTS, the
# strict CSP, sanitized error responses and Swagger gating.
NODE_ENV=development
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
*.pem
*.key
*.crt
*.p12
*.pfx
.*.sw*
node_modules
.vscode/
.eslintcache
.idea/
.node-xmlhttprequest*
.env
.env.*
!.env.example
coverage
coverage.json
.DS_Store
package-lock.json
/db
/db
/tmp
/sslcert/*
!/sslcert/README.md
/travis.pem.enc
88 changes: 65 additions & 23 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,37 +1,79 @@
FROM node:16.16.0-alpine
# Build stage: pulls the full toolchain, installs dev deps, produces the bundle.
FROM node:20.18.0-alpine AS build

LABEL maintainer="admin@xinfin.network"

WORKDIR /app

COPY package*.json ./

# Non-root build user to keep the filesystem layout predictable.
RUN apk --no-cache add \
bash \
git \
curl \
python3 \
build-base \
libffi-dev \
openssl-dev \
bzip2-dev \
zlib-dev \
readline-dev \
sqlite-dev \
&& curl https://pyenv.run | bash \
&& export PATH="/root/.pyenv/bin:$PATH" \
&& eval "$(pyenv init -)" \
&& eval "$(pyenv virtualenv-init -)" \
&& pyenv install 2.7.18 3.9.0 \
&& pyenv global 3.9.0 2.7.18 \
&& npm install --legacy-peer-deps
COPY . .
openssl-dev

COPY package*.json ./
# `--ignore-scripts` skips the native rebuild of legacy transitive deps
# (`sha3@1.x`, `keccak`, etc.) whose `binding.gyp` is incompatible with newer
# `node-gyp`/Node 20. The runtime path of this app uses pure-JS hashing, so the
# missing native bindings don't affect functionality. Without this flag the
# Docker build aborts during `npm install` on Alpine.
RUN npm install --legacy-peer-deps --ignore-scripts

COPY . .
RUN mkdir -p build/contracts \
&& mv abis/* build/contracts/ \
&& npm run build \
&& rm -rf node_modules \
&& npm install --production --legacy-peer-deps
&& cp abis/*.json build/contracts/ \
&& npm run build

# Runtime stage: only production dependencies + built artifacts. This removes
# the build toolchain and dev-only packages from the final image, shrinking
# both attack surface and image size.
FROM node:20.18.0-alpine AS runtime

LABEL maintainer="admin@xinfin.network"
WORKDIR /app

# Create an unprivileged user to run the app and hand it ownership of WORKDIR
# up-front so every subsequent step (npm install, mkdir tmp/sslcert, the
# COPY --chown directives) can run as that user. This keeps the container
# rootless from this point on AND avoids a final `chown -R` over the
# multi-million-file node_modules tree, which on overlay filesystems can
# easily take 10+ minutes per layer (CodeRabbit #49 — comment vs. behaviour
# mismatch in the previous revision).
RUN addgroup -S masternode && adduser -S masternode -G masternode \
&& chown masternode:masternode /app

USER masternode

COPY --from=build --chown=masternode:masternode /app/package*.json ./
RUN npm install --omit=dev --legacy-peer-deps --ignore-scripts \
&& npm cache clean --force

COPY --from=build --chown=masternode:masternode /app/build ./build
COPY --from=build --chown=masternode:masternode /app/abis ./abis
COPY --from=build --chown=masternode:masternode /app/apis ./apis
COPY --from=build --chown=masternode:masternode /app/app ./app
COPY --from=build --chown=masternode:masternode /app/commands ./commands
COPY --from=build --chown=masternode:masternode /app/config ./config
COPY --from=build --chown=masternode:masternode /app/contracts ./contracts
COPY --from=build --chown=masternode:masternode /app/docs ./docs
COPY --from=build --chown=masternode:masternode /app/helpers ./helpers
COPY --from=build --chown=masternode:masternode /app/middlewares ./middlewares
COPY --from=build --chown=masternode:masternode /app/models ./models
COPY --from=build --chown=masternode:masternode /app/validators ./validators
COPY --from=build --chown=masternode:masternode /app/abis.js ./abis.js
COPY --from=build --chown=masternode:masternode /app/cmd.js ./cmd.js
COPY --from=build --chown=masternode:masternode /app/crawl.js ./crawl.js
COPY --from=build --chown=masternode:masternode /app/elect.js ./elect.js
COPY --from=build --chown=masternode:masternode /app/helpers.js ./helpers.js
COPY --from=build --chown=masternode:masternode /app/index.js ./index.js
COPY --from=build --chown=masternode:masternode /app/index-prod.html ./index.html

RUN mkdir -p /app/tmp /app/sslcert

ENTRYPOINT ["npm"]
EXPOSE 3000
ENV NODE_ENV=production

CMD ["start"]
CMD ["node", "index.js"]
Loading