diff --git a/Dockerfile b/Dockerfile
index 2d51f81..5848ff8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,7 +4,7 @@ FROM node:20-alpine as build
WORKDIR /app
# Copy package files
-COPY package*.json ./
+COPY package.json package-lock.json ./
# Install dependencies
RUN npm ci
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 72df894..d44659e 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -6,7 +6,7 @@ WORKDIR /app
COPY package*.json ./
# Install dependencies
-RUN npm ci --only=production
+RUN npm install --only=production
# Copy source code
COPY . .
diff --git a/backend/src/index.js b/backend/src/index.js
index c72c45d..811f4f3 100644
--- a/backend/src/index.js
+++ b/backend/src/index.js
@@ -11,18 +11,26 @@ dotenv.config();
const app = express();
const port = process.env.PORT || 3001;
+// Trust proxy for rate limiting behind Traefik
+app.set('trust proxy', 1);
+
// Middleware
app.use(helmet());
app.use(express.json());
app.use(cors({
- origin: process.env.CORS_ORIGIN,
+ origin: process.env.CORS_ORIGIN || 'https://knck.pl',
methods: ['POST']
}));
// Rate limiting
const limiter = rateLimit({
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 900000, // 15 minutes
- max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 5 // 5 requests per window
+ max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 5, // 5 requests per window
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
+ keyGenerator: (req) => {
+ return req.ip || req.socket.remoteAddress;
+ }
});
app.use('/api/contact', limiter);
@@ -30,10 +38,34 @@ app.use('/api/contact', limiter);
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT),
- secure: false,
+ secure: false, // true for 465, false for other ports like 587
auth: {
+ type: 'login',
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
+ },
+ tls: {
+ rejectUnauthorized: false // Required for some SMTP servers
+ },
+ debug: true, // Enable debug logging
+ logger: true // Enable logger
+});
+
+// Verify SMTP connection configuration
+transporter.verify(function(error, success) {
+ if (error) {
+ console.error('SMTP connection error:', {
+ message: error.message,
+ code: error.code,
+ response: error.response,
+ command: error.command,
+ stack: error.stack,
+ host: process.env.SMTP_HOST,
+ port: process.env.SMTP_PORT,
+ user: process.env.SMTP_USER
+ });
+ } else {
+ console.log('SMTP server is ready to take our messages');
}
});
@@ -73,7 +105,13 @@ ${message}
res.status(200).json({ message: 'Email sent successfully' });
} catch (error) {
- console.error('Error sending email:', error);
+ console.error('Error sending email:', {
+ message: error.message,
+ code: error.code,
+ response: error.response,
+ command: error.command,
+ stack: error.stack
+ });
res.status(500).json({ error: 'Failed to send email' });
}
});
diff --git a/combined.yaml b/combined.yaml
new file mode 100644
index 0000000..cbfe89a
--- /dev/null
+++ b/combined.yaml
@@ -0,0 +1,160 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: knck-app
+ labels:
+ app: knck-app
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: knck-app
+ template:
+ metadata:
+ labels:
+ app: knck-app
+ spec:
+ containers:
+ - name: knck-frontend
+ image: knck-frontend:latest
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 80
+ resources:
+ requests:
+ cpu: "50m"
+ memory: "64Mi"
+ limits:
+ cpu: "100m"
+ memory: "128Mi"
+ readinessProbe:
+ httpGet:
+ path: /
+ port: 80
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ livenessProbe:
+ httpGet:
+ path: /
+ port: 80
+ initialDelaySeconds: 15
+ periodSeconds: 20
+ - name: knck-backend
+ image: knck-backend:latest
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 3001
+ env:
+ - name: PORT
+ value: "3001"
+ - name: NODE_ENV
+ value: "production"
+ - name: SMTP_HOST
+ valueFrom:
+ secretKeyRef:
+ name: knck-secrets
+ key: smtp-host
+ - name: SMTP_PORT
+ valueFrom:
+ secretKeyRef:
+ name: knck-secrets
+ key: smtp-port
+ - name: SMTP_USER
+ valueFrom:
+ secretKeyRef:
+ name: knck-secrets
+ key: smtp-user
+ - name: SMTP_PASS
+ valueFrom:
+ secretKeyRef:
+ name: knck-secrets
+ key: smtp-pass
+ - name: SMTP_FROM
+ valueFrom:
+ secretKeyRef:
+ name: knck-secrets
+ key: smtp-from
+ - name: SMTP_TO
+ valueFrom:
+ secretKeyRef:
+ name: knck-secrets
+ key: smtp-to
+ - name: CORS_ORIGIN
+ value: "https://knck.pl"
+ resources:
+ requests:
+ cpu: "100m"
+ memory: "128Mi"
+ limits:
+ cpu: "200m"
+ memory: "256Mi"
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 3001
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 3001
+ initialDelaySeconds: 15
+ periodSeconds: 20
+---
+kind: Ingress
+metadata:
+ name: knck-ingress
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
+ traefik.ingress.kubernetes.io/service.serversscheme: http
+ traefik.ingress.kubernetes.io/service.passhostheader: "true"
+ traefik.ingress.kubernetes.io/router.priority: "1"
+ cert-manager.io/cluster-issuer: letsencrypt-prod
+ acme.cert-manager.io/http01-edit-in-place: "true"
+ acme.cert-manager.io/http01-ingress-class: traefik
+spec:
+ tls:
+ - hosts:
+ - knck.pl
+ - api.knck.pl
+ secretName: knck-tls
+ rules:
+ - host: knck.pl
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: knck-app
+ port:
+ number: 80
+ - host: api.knck.pl
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: knck-app
+ port:
+ number: 3001
+---
+kind: Service
+metadata:
+ name: knck-app
+spec:
+ selector:
+ app: knck-app
+ ports:
+ - name: frontend
+ protocol: TCP
+ port: 80
+ targetPort: 80
+ - name: backend
+ protocol: TCP
+ port: 3001
+ targetPort: 3001
+ type: ClusterIP
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..49e17eb
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,26 @@
+version: '3.8'
+
+services:
+ frontend:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ ports:
+ - "80:80"
+ depends_on:
+ - backend
+
+ backend:
+ build:
+ context: ./backend
+ dockerfile: Dockerfile
+ ports:
+ - "3001:3001"
+ environment:
+ - SMTP_HOST=smtp.mail.me.com
+ - SMTP_PORT=587
+ - SMTP_USER=your-email@me.com
+ - SMTP_PASS=your-app-specific-password
+ - SMTP_FROM=your-email@me.com
+ - SMTP_TO=your-email@me.com
+ - CORS_ORIGIN=http://localhost
\ No newline at end of file
diff --git a/k8s/combined-deployment.yaml b/k8s/combined-deployment.yaml
index 15b99f6..1ed64ee 100644
--- a/k8s/combined-deployment.yaml
+++ b/k8s/combined-deployment.yaml
@@ -79,8 +79,6 @@ spec:
secretKeyRef:
name: knck-secrets
key: smtp-to
- - name: CORS_ORIGIN
- value: "https://knck.pl"
resources:
requests:
cpu: "100m"
diff --git a/k8s/combined-ingress.yaml b/k8s/combined-ingress.yaml
index 991a1e6..13fe691 100644
--- a/k8s/combined-ingress.yaml
+++ b/k8s/combined-ingress.yaml
@@ -16,7 +16,6 @@ spec:
tls:
- hosts:
- knck.pl
- - api.knck.pl
secretName: knck-tls
rules:
- host: knck.pl
@@ -29,10 +28,7 @@ spec:
name: knck-app
port:
number: 80
- - host: api.knck.pl
- http:
- paths:
- - path: /
+ - path: /api
pathType: Prefix
backend:
service:
diff --git a/k8s/secrets.yaml b/k8s/secrets.yaml
index b5ff575..6cd459c 100644
--- a/k8s/secrets.yaml
+++ b/k8s/secrets.yaml
@@ -4,10 +4,11 @@ metadata:
name: knck-secrets
type: Opaque
data:
- # These values should be base64 encoded
- smtp-host: c210cC5tYWlsLm1lLmNvbQ== # smtp.mail.me.com
- smtp-port: NTg3 # 587
- smtp-user: eW91ci1lbWFpbEBtZS5jb20= # your-email@me.com
- smtp-pass: eW91ci1hcHAtc3BlY2lmaWMtcGFzc3dvcmQ= # your-app-specific-password
- smtp-from: eW91ci1lbWFpbEBtZS5jb20= # your-email@me.com
- smtp-to: eW91ci1lbWFpbEBtZS5jb20= # your-email@me.com
\ No newline at end of file
+ # Replace these values with your base64 encoded actual values
+ # Example: echo -n "your-actual-value" | base64
+ smtp-host: REPLACE_WITH_YOUR_BASE64_ENCODED_SMTP_HOST
+ smtp-port: REPLACE_WITH_YOUR_BASE64_ENCODED_SMTP_PORT
+ smtp-user: REPLACE_WITH_YOUR_BASE64_ENCODED_SMTP_USER
+ smtp-pass: REPLACE_WITH_YOUR_BASE64_ENCODED_SMTP_PASSWORD
+ smtp-from: REPLACE_WITH_YOUR_BASE64_ENCODED_SMTP_FROM
+ smtp-to: REPLACE_WITH_YOUR_BASE64_ENCODED_SMTP_TO
\ No newline at end of file
diff --git a/src/components/LandingPage.tsx b/src/components/LandingPage.tsx
index 9fc8f00..0ba012b 100644
--- a/src/components/LandingPage.tsx
+++ b/src/components/LandingPage.tsx
@@ -23,13 +23,13 @@ const LandingPage: FC = () => {