# Deploying a Secure Contact Form Application with Kubernetes and Cloudflare Tunnel

## Introduction

In this comprehensive guide, we'll walk through setting up and deploying a secure, scalable contact-form backend using Python Flask and Kubernetes and exposing it securely to the Internet using Cloudflare Tunnel. By the end of this tutorial, you'll have a fully working backend service accessible globally, ideal for integrating with any front-end application.

## Prerequisites

* Basic knowledge of Kubernetes, Docker, and Python
    
* Cloudflare account and a registered domain
    
* Docker and Kubernetes installed locally or on your server
    
* setup a SendGrid account and get the API key
    

## Step 1: Create Your Flask Contact Form Application

Create a Flask app named `app.py` with email integration using SendGrid.

`app.py:`

```bash
from flask import Flask, request, jsonify
from flask_cors import CORS
import os
import logging
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail

app = Flask(__name__)
CORS(app)

@app.route('/contact-form', methods=['POST', 'OPTIONS'])
def contact_form():
    if request.method == "OPTIONS":
        response = jsonify({"message": "CORS Preflight OK"})
        response.headers.add("Access-Control-Allow-Origin", "*")
        response.headers.add("Access-Control-Allow-Methods", "POST, OPTIONS")
        response.headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization")
        return response, 200

    data = request.get_json()
    required_fields = ['name', 'email', 'subject', 'message']
    if not all(field in data for field in required_fields):
        return jsonify({"error": "Missing fields"}), 400

    sender_email = os.getenv("SENDER_EMAIL")
    receiver_email = os.getenv("RECEIVER_EMAIL")
    
    email_body = f"""
    <p><strong>Name:</strong> {data['name']}</p>
    <p><strong>Email:</strong> {data['email']}</p>
    <p><strong>Subject:</strong> {data['subject']}</p>
    <p><strong>Message:</strong></p><p>{data['message']}</p>
    """

    sg = SendGridAPIClient(os.getenv("SENDGRID_API_KEY"))
    email = Mail(from_email=sender_email, to_emails=receiver_email,
                 subject=data['subject'], html_content=email_body)
    sg.send(email)

    return jsonify({"message": "Form submitted successfully"}), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
```

`requirements.txt:`

```bash
flask
flask_cors
gunicorn
sendgrid
```

## Step 2: Dockerizing Your Application

Create a `Dockerfile` in the root directory:

```bash
FROM python:3.9
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "app:app"]
```

Build and push your Docker image:

```bash
docker build -t yourdockerhubusername/contact-form-app:latest .
docker push yourdockerhubusername/contact-form-app:latest
```

---

## Step 3: Deploying Application to Kubernetes

Create Kubernetes Deployment and Service files:

`deployment.yaml:`

```bash
apiVersion: apps/v1
kind: Deployment
metadata:
  name: contact-form-app
  namespace: contact-form
spec:
  replicas: 1
  selector:
    matchLabels:
      app: contact-form-app
  template:
    metadata:
      labels:
        app: contact-form-app
    spec:
      containers:
        - name: contact-form
          image: yourdockerhubusername/contact-form-app:latest
          ports:
            - containerPort: 5000
          env:
            - name: SENDGRID_API_KEY
              valueFrom:
                secretKeyRef:
                  name: sendgrid-secret
                  key: sendgrid_api_key
            - name: SENDER_EMAIL
              value: "your-sender-email@example.com"
            - name: RECEIVER_EMAIL
              value: "your-receiver-email@example.com"
```

`service.yaml:`

```bash
apiVersion: v1
kind: Service
metadata:
  name: contact-form-service
  namespace: contact-form
spec:
  selector:
    app: contact-form-app
  ports:
    - protocol: TCP
      port: 3344
      targetPort: 5000
  type: ClusterIP
```

### Kubernetes Secret

Create Kubernetes secret for SendGrid API:

```bash
kubectl create secret generic sendgrid-secret -n contact-form --from-literal=sendgrid_api_key='your-sendgrid-api-key'
```

Deploy:

```bash
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
```

---

## Step 4: Test Application using ClusterIP (Local Test)

Create a temporary debug pod:

```bash
kubectl run testcurl -n contact-form --image=radial/busyboxplus:curl -i --tty --rm
```

Inside pod run:

```bash
curl -X POST http://contact-form-service:3344/contact-form -H 'Content-Type: application/json' -d '{"name":"test","email":"test@test.com","subject":"test","message":"hello"}'
```

---

## Step 5: Setting Up Cloudflare Tunnel

1. Install Cloudflared:
    

```bash
sudo apt install cloudflared
```

2. Authenticate Cloudflare:
    

```bash
cloudflared tunnel login
```

3. Create a Tunnel:
    

```bash
cloudflared tunnel create contact-form-tunnel
```

4. Configure DNS via Cloudflare Dashboard:
    
    * Log into Cloudflare &gt; select domain &gt; DNS tab
        
    * Add a CNAME record:
        
        * Name: `contact` (your subdomain)
            
        * Target: `<tunnel-uuid>.cfargotunnel.com`
            

---

## Step 6: Cloudflare Kubernetes Deployment

`cloudflared-deployment.yaml`:

```bash
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cloudflare-tunnel
  namespace: contact-form
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cloudflare-tunnel
  template:
    metadata:
      labels:
        app: cloudflare-tunnel
    spec:
      containers:
        - name: cloudflare-tunnel
          image: cloudflare/cloudflared:latest
          args:
            - "tunnel"
            - "--no-autoupdate"
            - "run"
            - "--token"
            - "$(TUNNEL_TOKEN)"
          env:
            - name: TUNNEL_TOKEN
              valueFrom:
                secretKeyRef:
                  name: cloudflare-tunnel-secret
                  key: token
          volumeMounts:
            - name: config-volume
              mountPath: /etc/cloudflared
      volumes:
        - name: config-volume
          configMap:
            name: cloudflare-config
```

`cloudflared-config.yaml:`

```bash
apiVersion: v1
kind: ConfigMap
metadata:
  name: cloudflared-config
  namespace: contact-form
data:
  config.yml: |
    ingress:
      - hostname: contact.yourdomain.com
        service: http://contact-form-service.contact-form.svc.cluster.local:3344
      - service: http_status:404
```

**Cloudflare secret**:

```bash
kubectl create secret generic cloudflare-tunnel-secret --from-literal=token='your-tunnel-token' -n contact-form
```

Deploy Cloudflared:

```bash
kubectl apply -f cloudflared-config.yaml -f cloudflared-deployment.yaml
```

---

## Step 7: Final Test

```bash
curl -X POST https://contact.yourdomain.com/contact-form -H 'Content-Type: application/json' -d '{"name":"test","email":"test@test.com","subject":"hello","message":"world"}'
```

---

## Frontend Integration

Use the above URL as an API endpoint for form submissions from your front end.

## Future Scope

* Integrate a database to store submissions.
    
* Set up analytics and monitoring.
    

## Conclusion

You now have a secure, scalable contact form backend ready for production use.
