The big picture.
Five free services, each with one job. You'll create an account on each one using your business email, then connect them.
GitHub
The filing cabinet. Holds your website's files.
Cloudflare
The storefront. Shows your site to the world at your own address.
Supabase
The notebook. Saves what visitors send you, like contact forms.
Resend
The mail carrier. Sends one-to-one automatic emails like "new message" alerts.
Mailchimp
The megaphone. Sends newsletters and promotions to your whole list.
Your details
Type these in once and every instruction in this guide fills them in for you. They stay in your own browser and are never sent anywhere.
Gather your supplies
- Your business email and access to its inbox (you'll click lots of verification links).
- Your phone, for two-step login codes.
- A password manager (Bitwarden, 1Password, or your browser's built-in one). You'll create five passwords and two secret keys.
- A domain name idea, or the login for a domain you already own.
Use your business email for every sign-up
Sign up for all five services with . Keeping everything under one business email means you can hand the business off later or add a helper without untangling personal accounts.
Best setup: an email at your own domain (like ). Mailchimp needs one to send newsletters reliably. If your business email is a Gmail address, the Cloudflare tab shows how to get a free address at your domain.Learn the two rules of secret keys
Some services give you a long code called an API key. Think of it like a house key.
- Save it in your password manager the moment you see it. Most services only show it once.
- Never paste a secret key into your website files or GitHub. You'll put it in Cloudflare's locked "Secrets" box instead.
Claim your address.
Cloudflare will host your site and manage your domain's settings (called DNS). We start here because the email services need those settings later.
Create your account
Go to dash.cloudflare.com/sign-up. Enter and a strong password. Open the verification email and click the link.
Turn on two-step login
Click the person icon (top right) → Profile → Authentication → Two-Factor Authentication. Scan the code with an authenticator app and save the backup codes in your password manager.
Get your domain
If you don't own one yet: in the left menu choose Domain Registration → Register Domains. Search for , add it to your cart and check out. Cloudflare sells domains at cost with no markup, and it's set up automatically.
If you already own one elsewhere (GoDaddy, Namecheap, Squarespace…): click Add a domain, type , pick the Free plan, and continue. Cloudflare shows you two "nameservers." Log in where you bought the domain, find "Nameservers," choose "Custom," and paste in Cloudflare's two. Changes can take up to 24 hours; Cloudflare emails you when the domain is Active.
Already have email at this domain? Before switching nameservers, open DNS → Records in Cloudflare and make sure the records called MX were copied over. If they're missing, your email will stop working. Copy them from your old provider if needed.Optional: a free email address at your domain
Only needed if your business email is a Gmail/Outlook address. Open your domain → Email → Email Routing → Get started. Create an address like hello@ and forward it to your existing inbox. Cloudflare adds the needed records for you.
Skip this if you already use Google Workspace or Microsoft 365 at your domain.
Set up the filing cabinet.
Every file of your website lives here. When you change a file, your live site updates on its own within a minute or two.
Create your account
Go to github.com/signup and sign up with . Pick a username that matches your business. Enter the code GitHub emails you.
GitHub will ask you to turn on two-step login. Do it now with the same authenticator app.
Create a repository (your site's folder)
Click the + at the top right → New repository.
- Repository name: something like
website - Visibility: Private is fine
- Tick Add a README file
Click Create repository.
- Repository name: something like
Add your home page
Already have website files (from a designer or a site builder export)? Click Add file → Upload files, drag them in, then click Commit changes. Your main page must be named
index.html.Starting fresh? Click Add file → Create new file. Name it
index.html, paste the starter page below, then click Commit changes. It already has a contact form and a spot for your newsletter signup.index.html<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title></title> <style> body { font-family: system-ui, sans-serif; max-width: 640px; margin: 40px auto; padding: 0 16px; line-height: 1.6; } input, textarea, button { display: block; width: 100%; margin: 6px 0 16px; padding: 10px; font: inherit; } button { background: #FF6B35; color: #fff; border: 0; border-radius: 8px; cursor: pointer; } </style> </head> <body> <h1></h1> <p>Welcome! Tell people what you do here.</p> <h2>Contact us</h2> <form method="POST" action="/api/contact"> <label>Name <input name="name" required></label> <label>Email <input name="email" type="email" required></label> <label>Message <textarea name="message" rows="4"></textarea></label> <button type="submit">Send</button> </form> <h2>Join our newsletter</h2> <!-- Paste your Mailchimp signup form here (see the Mailchimp tab) --> </body> </html>Add a thank-you page
Click Add file → Create new file, name it
thanks.html, paste this, and click Commit changes. Visitors land here after sending the contact form.thanks.html<!doctype html> <html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Thank you</title></head> <body style="font-family: system-ui, sans-serif; max-width: 640px; margin: 40px auto; padding: 0 16px;"> <h1>Thanks! We got your message.</h1> <p>We'll reply soon. <a href="/">Back to the home page</a></p> </body> </html>
Put it on the internet.
Connect GitHub to Cloudflare Pages. From now on, every change you save in GitHub goes live automatically.
Start a Pages project
In Cloudflare's left menu choose Compute → Workers & Pages → Create application. Pick the Pages option, then Connect to Git.
Only see "Workers"? Cloudflare moves its buttons around. Look for a small link like "Looking to deploy Pages? Get started." This guide's contact form needs Pages.Let Cloudflare see your GitHub
Click Connect GitHub. On the GitHub screen choose Only select repositories, pick your
websiterepository, and click Install & Authorize.Deploy
Select your repository → Begin setup. Use these settings:
- Project name: your business name (this becomes your free test address)
- Framework preset: None
- Build command: leave empty
- Build output directory: leave empty
Click Save and Deploy. In about a minute you'll get an address ending in .pages.dev. Open it. That's your site, live!
Using a site builder or framework (Astro, Next.js, Vite)? Pick it from the preset list and Cloudflare fills in the build settings.Use your own domain
Open your project → Custom domains → Set up a custom domain. Type and click Activate domain. Repeat with www. so both versions work.
Wait a few minutes, then visit https://. The padlock means it's secure. Cloudflare handles that for free.
A place to save everything.
Supabase is your database. We'll make one table that stores every message sent through your contact form, so nothing gets lost in an inbox.
Create your account
Go to supabase.com → Start your project. The easiest choice is Continue with GitHub, which uses the account you just made. Or sign up with .
Create an organization and project
Name the organization and choose the Free plan. Then create a project:
- Name:
website - Database password: click Generate a password and save it in your password manager
- Region: the one closest to your customers
Click Create new project and wait about two minutes.
- Name:
Create your contacts table
In the left menu open SQL Editor. Paste the code below and click Run. You should see "Success."
SQL · creates the table and lets your form add rowscreate table public.contacts ( id bigint generated always as identity primary key, created_at timestamptz not null default now(), name text, email text not null, message text ); alter table public.contacts enable row level security; grant insert on public.contacts to anon; create policy "Website visitors can send messages" on public.contacts for insert to anon with check (true);In plain English: this makes a "contacts" table and lets your website add messages, but not read or delete anyone's data.
Copy your project address and public key
Click Project Settings (gear icon, bottom left). Under Data API copy the Project URL (looks like
https://abcd1234.supabase.co). Under API Keys copy the Publishable key (starts withsb_publishable_).Save both in your password manager. You'll use them on the Contact form tab.
Leave the secret key alone. The key starting withsb_secret_can read and delete everything. You don't need it for this guide. Never share it.See your messages anytime
Open Table Editor → contacts. Every form submission appears as a new row. You can export them with the Export button as a spreadsheet file.
Hire a mail carrier.
Resend sends emails from your website automatically, like "You've got a new message" alerts, receipts and login links. They come from your own domain, so they land in inboxes instead of spam.
Create your account
Go to resend.com/signup and sign up with . Confirm your email.
Add your domain
Click Domains → Add Domain. Type , choose the region closest to you, and click Add. Resend shows a short list of records (codes) that prove you own the domain.
Add the records to Cloudflare
Easy way: if Resend shows an Auto configure or "Sign in to Cloudflare" button, click it and approve. Done.
Manual way: open a second browser tab with Cloudflare → your domain → DNS → Records. For each row in Resend, click Add record and copy the Type, Name and Value exactly. Leave TTL on Auto.
Type Name (example) What it does TXT resend._domainkeyYour email "signature" (DKIM) MX sendHandles bounced emails TXT sendLists who may send for you (SPF) Back in Resend, click Verify DNS Records. It can take from a few minutes to a few hours. You'll see a green Verified.
Add a DMARC record (helps both Resend and Mailchimp)
In Cloudflare DNS → Records, first check there isn't already a TXT record named
_dmarc. There can only be one. If none exists, click Add record: Type TXT, Name_dmarc, and this value:DMARC valuev=DMARC1; p=none; rua=mailto:Create your API key
Click API Keys → Create API Key. Name it
website, choose Sending access, select your domain, and click Add.Copy it now. It starts withre_and Resend only shows it once. Paste it straight into your password manager.Optional: send Supabase login emails through Resend
Only if you'll add customer logins later. In Supabase open Authentication → Emails → SMTP Settings, switch on custom SMTP and enter:
Host smtp.resend.comPort 465Username resendPassword your Resend API key Sender email noreply@ Sender name
Make the form work.
One small file ties it all together. When someone fills in your form, it saves the message to Supabase and emails you through Resend.
Add the form handler file in GitHub
In your
websiterepository click Add file → Create new file. In the name box type exactlyfunctions/api/contact.js. Typing the slashes creates the folders for you. Paste the code below and click Commit changes.functions/api/contact.jsexport async function onRequestPost({ request, env }) { const form = await request.formData(); const name = String(form.get("name") || "").slice(0, 200); const email = String(form.get("email") || "").slice(0, 200); const message = String(form.get("message") || "").slice(0, 5000); if (!email.includes("@")) { return new Response("Please go back and enter a valid email.", { status: 400 }); } // 1. Save the message in Supabase const saved = await fetch(env.SUPABASE_URL + "/rest/v1/contacts", { method: "POST", headers: { apikey: env.SUPABASE_KEY, "Content-Type": "application/json", Prefer: "return=minimal" }, body: JSON.stringify({ name, email, message }) }); if (!saved.ok) { return new Response("Sorry, your message could not be saved. Please email us instead.", { status: 500 }); } // 2. Email yourself through Resend await fetch("https://api.resend.com/emails", { method: "POST", headers: { Authorization: "Bearer " + env.RESEND_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ from: env.FROM_EMAIL, to: env.NOTIFY_EMAIL, reply_to: email, subject: "New website message from " + (name || email), text: "Name: " + name + "\nEmail: " + email + "\n\n" + message }) }); // 3. Send the visitor to the thank-you page return Response.redirect(new URL("/thanks.html", request.url).toString(), 303); }Give Cloudflare your keys
In Cloudflare open Workers & Pages → your project → Settings → Variables and Secrets → Add. Add these five, one at a time, for Production:
Variable name Type Value SUPABASE_URLText Your Supabase Project URL SUPABASE_KEYText Your Supabase publishable key RESEND_API_KEYSecret Your Resend key (starts with re_)FROM_EMAILText <noreply@> NOTIFY_EMAILText Names must match exactly, capital letters included. Click Save.
Redeploy so the keys take effect
Keys only apply to the next update. Go to your project's Deployments tab, click the ⋯ menu on the newest one, and choose Retry deployment.
Test it
Visit https://, fill in the contact form with your own details, and send. Within a minute you should see:
- the thank-you page,
- a new row in Supabase → Table Editor → contacts,
- an email in (check spam the first time and mark it "Not spam").
Row saved but no email? Check that Resend says Verified and thatFROM_EMAILuses your domain. Resend's Logs page shows why an email failed.
Grow your list.
Mailchimp collects newsletter signups on your site and sends your promotions, announcements and welcome emails to everyone at once.
Create your account
Go to mailchimp.com and choose the Free plan. Sign up with and confirm it.
Mailchimp asks for a business mailing address. Anti-spam law requires one in every marketing email footer. A PO box or registered agent address works if you'd rather not share your home.
Set up your audience
Your "audience" is your mailing list. Mailchimp creates one for you. Go to Audience → Settings → Audience name and defaults. Set the from-name to and the from-email to .
Verify and authenticate your domain
Click your profile icon → Account & billing → Domains → Add & Verify Domain. Enter , then type in the code Mailchimp emails you.
Next click Start Authentication and choose Cloudflare as your provider. Mailchimp shows two or three records (mostly CNAME records named like
k2._domainkey). Add each one in Cloudflare DNS → Records, then click Authenticate Domain.Important: when adding a CNAME record in Cloudflare, click the orange cloud so it turns grey ("DNS only"). If it stays orange, Mailchimp can't verify it. You already added the DMARC record on the Resend tab, so skip it here if Mailchimp asks.Put a signup form on your website
Go to Audience → Signup forms → Embedded form. Adjust the fields if you like, then click Continue and Copy code.
In GitHub open
index.html, click the pencil icon to edit, find the line that says Paste your Mailchimp signup form here, paste the code right under it, and click Commit changes. Your site updates in about a minute.Send new subscribers a welcome email
Go to Automations and choose the Welcome new subscribers template. Write a short hello (who you are, what they'll get, maybe a discount code), then turn it on.
Free plan limits change often. If an automation shows a lock icon, it needs a paid plan. A simple first newsletter works on the free plan.Know who sends what
Email Sent by Newsletters, promotions, announcements Mailchimp Welcome series for subscribers Mailchimp Contact form alerts, receipts, password resets Resend Your day-to-day replies to customers Your business inbox
Pre-launch checklist.
Run through these before you tell the world. Each one takes a minute.
Your site opens on both addresses
https:// and https://www. both load, with a padlock in the address bar. Check on your phone too.
Contact form test passes
A test message shows up in Supabase and as an email in your inbox.
Newsletter test passes
Sign up with a personal email. You should get Mailchimp's confirmation and welcome emails, and see yourself under Audience → All contacts.
Domain shows green everywhere
Resend says Verified. Mailchimp says Authenticated. Cloudflare says Active.
Secrets are safe
In GitHub, use the search box in your repository to search for
re_andsb_secret. Nothing should come up. If a key ever lands in GitHub, delete it in Resend or Supabase and make a new one.Two-step login is on for all five accounts
Cloudflare, GitHub, Supabase, Resend and Mailchimp. All passwords and keys are in your password manager.
Add a privacy policy page
Because you collect names and emails, add a short
privacy.htmlpage in GitHub explaining what you collect and why, and link to it from your home page. Free generators online can draft one for you.Keep Supabase awake
Free Supabase projects pause after about a week with no activity. A steady trickle of form submissions keeps it awake. If it pauses, open the project in Supabase and click Restore.
Host this guide yourself.
This whole guide is one file. Put it on your own Cloudflare account and share the link with anyone building their own site.
Get the file
Save this page to your computer. In your browser choose File → Save Page As and pick Webpage, HTML only. Name it
index.htmland put it in a new folder named something likelaunch-guide.Upload it to Cloudflare
In your personal Cloudflare account go to Workers & Pages → Create application → Pages → Upload assets (sometimes labeled "Drag and drop your files").
Give the project a name like
website-launch-guide, click Create project, drag in yourlaunch-guidefolder, and click Deploy site.Share the link
You'll get an address like website-launch-guide.pages.dev. Send it to anyone. Each person's details and checkmarks are saved only in their own browser, so nobody sees anyone else's info.
Want it on your own domain? Use Custom domains in the project, like the Go live tab shows.
Update it later
Edit the file, then in the project click Create deployment and upload the folder again.