Your endâtoâend guide to turning a simple Flask app into a productionâready, SSLâsecured service that sells itself.
đ TL;DR
-
Start from the
ciel_auto_1._write_a_flask_(or_fastapi).pytemplate. -
Add two routes â a landing page (
/) and a Stripe checkout (/checkout/<plan>). - Dockerize the app and run it behind nginx on a VPS (169.58.38.67) listening on portâŻ80.
- Secure everything with Letâs Encrypt (autoârenew).
-
Publish the site at
https://cielâservices.com. - Create a 2âminute YouTube promo, embed the checkout link, and push the video.
- Update three existing Dev.to posts with a CTA to the new URL.
- Automate social posts (Twitter, Reddit, LinkedIn) every 12âŻh using NewsAPI.
- Reward the first 5 customers with a oneâtime âLAUNCH10â discount.
Below is a complete Dev.toâready markdown article (500âŻ+âŻwords) that walks you through each step, includes readyâtoâcopy code, and even drops a couple of affiliate links for the tools we love.
đŻ Why This Project Matters
AI, crypto, geopolitics, and data analysis are hot topicsâbut building a product that actually makes money is still a pain point. By the end of this guide youâll have a live SaaS storefront that sells a subscription plan (or any digital product) without writing a single line of JavaScript for the checkout flow. All you need is a Python web framework, Stripe, Docker, and a bit of Bash.
Pro tip: The same pattern works for any AIâdriven API (e.g., a sentimentâanalysis endpoint) or cryptoâpriceâalert service. Just swap the business logic inside the Flask route.
đ ď¸ 1. Base Code â ciel_auto_1._write_a_flask_(or_fastapi).py
Below is a minimal Flask skeleton (you can replace it with FastAPI if you prefer). Save it as app.py.
# app.py
import os
from flask import Flask, render_template, redirect, url_for, abort
import stripe
app = Flask(__name__)
# -------------------------------------------------
# Stripe configuration â replace with your own keys
# -------------------------------------------------
stripe.api_key = os.getenv("STRIPE_SECRET_KEY")
DOMAIN = os.getenv("DOMAIN", "https://ciel-services.com") # used for redirects
# -------------------------------------------------
# Landing page â product overview
# -------------------------------------------------
@app.route("/")
def landing():
# In a real app youâd pull this from a DB or CMS
product = {
"name": "Ciel AI Insight",
"description": "AIâpowered data analysis for crypto traders & geopolitics enthusiasts.",
"price_monthly": "$19.99/mo",
"price_yearly": "$199.99/yr",
"features": [
"Realâtime market sentiment",
"Geoârisk heatmaps",
"Custom alerts",
"API access"
],
"testimonials": [
{"author": "Alice", "text": "Gameâchanger for my crypto portfolio."},
{"author": "Bob", "text": "The geopolitics dashboard saved me $5k last quarter."}
]
}
return render_template("landing.html", product=product)
# -------------------------------------------------
# Checkout â creates a Stripe Checkout Session
# -------------------------------------------------
@app.route("/checkout/<plan>")
def checkout(plan):
if plan not in ("monthly", "yearly"):
abort(404)
# Prices created in Stripe Dashboard â use your own IDs
price_id = {
"monthly": "price_1MxxxxxxMonthly",
"yearly": "price_1MxxxxxxYearly"
}[plan]
try:
session = stripe.checkout.Session.create(
payment_method_types=["card"],
line_items=[{
"price": price_id,
"quantity": 1,
}],
mode="subscription",
discounts=[{
"coupon": os.getenv("STRIPE_COUPON_ID") # optional discount
}] if os.getenv("STRIPE_COUPON_ID") else None,
success_url=f"{DOMAIN}/success?session_id={{CHECKOUT_SESSION_ID}}",
cancel_url=f"{DOMAIN}/cancel",
)
return redirect(session.url, code=303)
except Exception as e:
return str(e), 400
# -------------------------------------------------
# Simple success / cancel pages
# -------------------------------------------------
@app.route("/success")
def success():
return "â
Payment successful! Check your email for the receipt."
@app.route("/cancel")
def cancel():
return "â Checkout cancelled. Feel free to try again!"
if __name__ == "__main__":
# Bind to 0.0.0.0 so Docker can expose it
app.run(host="0.0.0.0", port=5000, debug=False)
Templates (templates/landing.html) can be simple HTML with placeholders for the product data. Feel free to style with Tailwind or Bootstrapânothing in this guide depends on a particular CSS framework.
đŚ 2. Dockerize the App
Create a Dockerfile in the project root:
# Dockerfile
FROM python:3.12-slim
# Install system dependencies (optional)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Set workdir
WORKDIR /app
# Install Python deps
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy source
COPY . .
# Expose Flask default port
EXPOSE 5000
# Run the app
CMD ["python", "app.py"]
requirements.txt:
Flask==3.0.3
stripe==9.9.0
gunicorn==22.0.0 # optional, for production
Build and test locally:
docker build -t ciel-saas .
docker run -d -p 5000:5000 -e STRIPE_SECRET_KEY=sk_test_... \
-e STRIPE_COUPON_ID=coupon_... ciel-saas
Visit http://localhost:5000 â you should see the landing page.
đ 3. Deploy on VPS (169.58.38.67) with Nginx Reverse Proxy
3.1 Install Docker & DockerâCompose
# On the VPS
apt update && apt install -y docker.io docker-compose nginx certbot python3-certbot-nginx
systemctl enable docker
3.2 Create a docker-compose.yml
yaml
version: "3.8"
services:
web:
image: ciel-saas:latest
build: .
container_name: ciel_web
restart: unless-stopped
environment:
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- STRIPE_COUPON_ID=${STRIPE_COUPON_ID}
- DOMAIN=https://ciel-services.com
Top comments (0)