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:
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:
flask
flask_cors
gunicorn
sendgrid
Step 2: Dockerizing Your Application
Create a Dockerfile
in the root directory:
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:
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:
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:
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:
kubectl create secret generic sendgrid-secret -n contact-form --from-literal=sendgrid_api_key='your-sendgrid-api-key'
Deploy:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Step 4: Test Application using ClusterIP (Local Test)
Create a temporary debug pod:
kubectl run testcurl -n contact-form --image=radial/busyboxplus:curl -i --tty --rm
Inside pod run:
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
- Install Cloudflared:
sudo apt install cloudflared
- Authenticate Cloudflare:
cloudflared tunnel login
- Create a Tunnel:
cloudflared tunnel create contact-form-tunnel
Configure DNS via Cloudflare Dashboard:
Log into Cloudflare > select domain > DNS tab
Add a CNAME record:
Name:
contact
(your subdomain)Target:
<tunnel-uuid>.cfargotunnel.com
Step 6: Cloudflare Kubernetes Deployment
cloudflared-deployment.yaml
:
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:
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:
kubectl create secret generic cloudflare-tunnel-secret --from-literal=token='your-tunnel-token' -n contact-form
Deploy Cloudflared:
kubectl apply -f cloudflared-config.yaml -f cloudflared-deployment.yaml
Step 7: Final Test
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.
Subscribe to my newsletter
Read articles from Aliasgar Husain directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
