Skip to content

Commit cf5d741

Browse files
committed
feat: enhance production readiness and security features
- Updated .gitignore to include additional environment files and logs - Expanded README with production deployment instructions and required environment variables - Integrated security middleware (Helmet, rate limiting, compression) in app.js - Added production-specific validations for environment variables in config.js - Improved Dockerfile for better security and performance - Created a CI/CD pipeline in GitHub Actions for automated testing and security audits - Added a production readiness verification script to ensure deployment requirements are met - Updated package.json scripts for clearer development and production commands
1 parent 6d98e48 commit cf5d741

11 files changed

Lines changed: 416 additions & 10 deletions

File tree

.dockerignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
node_modules
2+
npm-debug.log
3+
.env
4+
.env.*
5+
.git
6+
.gitignore
7+
README.md
8+
Dockerfile
9+
.dockerignore
10+
coverage
11+
.nyc_output
12+
logs/*.log

.github/workflows/nodejs.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [18.x, 20.x]
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v3
20+
21+
- name: Use Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v3
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
cache: 'npm'
26+
27+
- name: Install dependencies
28+
run: npm ci
29+
30+
- name: Run tests
31+
run: npm test
32+
env:
33+
NODE_ENV: test
34+
35+
- name: Run security audit
36+
run: npm audit --audit-level moderate

.gitignore

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,45 @@
1+
# Environment variables
12
.env
2-
/node_modules
3+
.env.local
4+
.env.production
5+
.env.test
6+
7+
# Dependencies
8+
/node_modules
9+
npm-debug.log*
10+
yarn-debug.log*
11+
yarn-error.log*
12+
13+
# Logs
14+
logs/
15+
*.log
16+
17+
# Runtime data
18+
pids
19+
*.pid
20+
*.seed
21+
*.pid.lock
22+
23+
# Coverage directory used by tools like istanbul
24+
coverage/
25+
.nyc_output
26+
27+
# IDE/Editor files
28+
.vscode/
29+
.idea/
30+
*.swp
31+
*.swo
32+
*~
33+
34+
# OS generated files
35+
.DS_Store
36+
.DS_Store?
37+
._*
38+
.Spotlight-V100
39+
.Trashes
40+
ehthumbs.db
41+
Thumbs.db
42+
43+
# Build outputs
44+
dist/
45+
build/

Dockerfile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Use official Node.js runtime as base image
2+
FROM node:18-alpine
3+
4+
# Set working directory
5+
WORKDIR /app
6+
7+
# Copy package files
8+
COPY package*.json ./
9+
10+
# Install dependencies
11+
RUN npm ci --only=production && npm cache clean --force
12+
13+
# Create non-root user
14+
RUN addgroup -g 1001 -S nodejs && \
15+
adduser -S appuser -u 1001
16+
17+
# Copy application code
18+
COPY . .
19+
20+
# Create logs directory with proper permissions
21+
RUN mkdir -p logs && chown -R appuser:nodejs logs
22+
23+
# Switch to non-root user
24+
USER appuser
25+
26+
# Expose port
27+
EXPOSE 5000
28+
29+
# Health check
30+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
31+
CMD node -e "require('http').get('http://localhost:5000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"
32+
33+
# Start application
34+
CMD ["node", "app.js"]

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node app.js

README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,90 @@ The app will run at [http://localhost:5000](http://localhost:5000)
132132

133133
---
134134

135+
## 🚀 Production Deployment
136+
137+
### Required Environment Variables
138+
139+
Set these environment variables in your hosting provider:
140+
141+
```env
142+
# Database (Required)
143+
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/notes-app
144+
145+
# Google OAuth (Required)
146+
GOOGLE_CLIENT_ID=your_google_client_id
147+
GOOGLE_CLIENT_SECRET=your_google_client_secret
148+
GOOGLE_CALLBACK_URL=https://yourdomain.com/google/callback
149+
150+
# Security (Required for production)
151+
SESSION_SECRET=your_super_secret_random_string_here
152+
NODE_ENV=production
153+
PORT=5000
154+
155+
# Optional Features
156+
HUGGING_FACE_API=your_hugging_face_token
157+
REDIS_URL=redis://localhost:6379
158+
DOMAIN=yourdomain.com
159+
160+
# Email (Optional)
161+
SMTP_HOST=smtp.gmail.com
162+
SMTP_PORT=587
163+
SMTP_USER=your_email@gmail.com
164+
SMTP_PASS=your_app_password
165+
SMTP_FROM=noreply@yourdomain.com
166+
```
167+
168+
### Deploy to Heroku
169+
170+
1. Install Heroku CLI
171+
2. Login and create app:
172+
```bash
173+
heroku login
174+
heroku create your-notes-app
175+
```
176+
177+
3. Set environment variables:
178+
```bash
179+
heroku config:set NODE_ENV=production
180+
heroku config:set MONGODB_URI=your_mongodb_uri
181+
heroku config:set SESSION_SECRET=your_secret
182+
# ... add all other required vars
183+
```
184+
185+
4. Deploy:
186+
```bash
187+
git add .
188+
git commit -m "Deploy to production"
189+
git push heroku main
190+
```
191+
192+
### Deploy with Docker
193+
194+
1. Build image:
195+
```bash
196+
docker build -t notes-app .
197+
```
198+
199+
2. Run container:
200+
```bash
201+
docker run -d \
202+
-p 5000:5000 \
203+
-e NODE_ENV=production \
204+
-e MONGODB_URI=your_mongodb_uri \
205+
-e SESSION_SECRET=your_secret \
206+
--name notes-app \
207+
notes-app
208+
```
209+
210+
### Deploy to Render/Railway
211+
212+
1. Connect your GitHub repository
213+
2. Set environment variables in the dashboard
214+
3. Use build command: `npm install`
215+
4. Use start command: `npm start`
216+
217+
---
218+
135219
## 🔄 Real-time Collaboration
136220

137221
This app includes collaborative editing powered by Socket.IO:

app.js

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ const express = require('express');
44
const http = require('http');
55
const expressLayouts = require('express-ejs-layouts');
66
const methodOverride = require('method-override');
7+
const helmet = require('helmet');
8+
const rateLimit = require('express-rate-limit');
9+
const compression = require('compression');
710
const { connectDB } = require('./server/config/db');
811
const { getConfig } = require('./server/config/config');
912
const session = require('express-session');
@@ -18,6 +21,9 @@ if (config.NODE_ENV === 'production') {
1821
app.set('trust proxy', 1);
1922
}
2023

24+
// Compression middleware
25+
app.use(compression());
26+
2127
// Winston logger setup
2228
const winston = require('winston');
2329
const morgan = require('morgan');
@@ -88,22 +94,66 @@ app.use(methodOverride("_method"));
8894
// Connect to database
8995
connectDB();
9096

91-
// Static files
92-
app.use(express.static('public'));
93-
94-
// Templating engine
95-
app.use(expressLayouts);
96-
app.set('layout', './layouts/main');
97-
app.set('view engine', 'ejs');
97+
// Security middleware - Helmet with EJS-friendly CSP
98+
app.use(helmet({
99+
contentSecurityPolicy: {
100+
directives: {
101+
defaultSrc: ["'self'"],
102+
// Allow Google Fonts stylesheet
103+
styleSrc: [
104+
"'self'",
105+
"'unsafe-inline'",
106+
"https://cdn.jsdelivr.net",
107+
"https://cdnjs.cloudflare.com",
108+
"https://fonts.googleapis.com"
109+
],
110+
scriptSrc: [
111+
"'self'",
112+
"'unsafe-inline'",
113+
"https://cdn.jsdelivr.net",
114+
"https://cdnjs.cloudflare.com",
115+
"https://cdn.socket.io"
116+
],
117+
imgSrc: ["'self'", "data:", "https:"],
118+
// Allow Google Fonts font files
119+
fontSrc: [
120+
"'self'",
121+
"data:",
122+
"https://cdn.jsdelivr.net",
123+
"https://cdnjs.cloudflare.com",
124+
"https://fonts.gstatic.com"
125+
],
126+
connectSrc: ["'self'", "ws:", "wss:"]
127+
}
128+
}
129+
}));
130+
131+
// Rate limiting
132+
const limiter = rateLimit({
133+
windowMs: config.SECURITY.rateLimitWindow, // from config
134+
max: config.SECURITY.rateLimitRequests,
135+
message: 'Too many requests from this IP, please try again later.',
136+
standardHeaders: true,
137+
legacyHeaders: false,
138+
});
139+
app.use(limiter);
98140

99-
// Security middleware
141+
// Additional security headers (keeping existing ones for compatibility)
100142
app.use((req, res, next) => {
101143
res.setHeader('X-Content-Type-Options', 'nosniff');
102144
res.setHeader('X-Frame-Options', 'DENY');
103145
res.setHeader('X-XSS-Protection', '1; mode=block');
104146
next();
105147
});
106148

149+
// Static files
150+
app.use(express.static('public'));
151+
152+
// Templating engine
153+
app.use(expressLayouts);
154+
app.set('layout', './layouts/main');
155+
app.set('view engine', 'ejs');
156+
107157
// API versioning
108158
app.use('/api/v1/notes', require('./server/routes/api/v1/notes'));
109159

0 commit comments

Comments
 (0)