
SnapDeploy
From source code to infrastructure in 5 minute, not hours
It costs me $4.15/day to run a free tier — here's the full breakdown
I'm a solo founder running a container hosting platform. Deploy for free, pay when you need always-on uptime. Classic freemium.
Everyone asks: "How do you afford a free tier?"
Here's the honest answer with real numbers.
What the free tier actually costs me
My production AWS account runs about $4.15/day. That covers everything — the platform itself, all user containers, load balancers, DNS, monitoring.
The breakdown:
- ECS Fargate (platform + user containers): ~$2.10/day
- Application Load Balancer: ~$0.55/day
- DynamoDB (24 tables): ~$0.30/day
- ECR (container images): ~$0.20/day
- Route53 + CloudWatch + misc: ~$1.00/day
That's about $125/month to run the entire production environment.
The trick: auto-sleep
Free containers auto-sleep after 15 minutes of idle time. Sleeping containers cost me almost nothing — no Fargate compute charges, just a few cents of metadata storage.
When traffic arrives, the container wakes up in about 60 seconds. The user sees a loading page, the container spins up behind it, and they get their app.
This means I'm only paying Fargate costs for containers that are actively serving traffic. Most free-tier containers sleep 90%+ of the time.
The dev account trick
I run two AWS accounts. Production handles real users. Dev handles my own development and testing.
Dev account costs ~$2.98/day. But here's the thing — I built shutdown scripts that scale everything to zero when I'm not working. ECS services go to 0 tasks, EC2 instances stop. I run them at end of day and start everything back up in the morning. Takes about 2-3 minutes to restart.
That saves me roughly $16/day on dev costs when I'm not actively coding.
The DynamoDB lesson
This one cost me real money. I originally set up all 33 DynamoDB tables with provisioned capacity and auto-scaling. Sounds smart, right?
Auto-scaling kept thrashing — scaling up for tiny traffic spikes, then slowly scaling back down, then scaling up again. The result: $743/month in DynamoDB costs alone. For a platform with near-zero traffic.
I switched every table to on-demand billing in a single afternoon. New cost: $214/month. Saved $529/month by changing one setting on each table.
On-demand charges per-request instead of per-hour. When you have low, unpredictable traffic (which is every early-stage startup), on-demand wins by a landslide.
Can this sustain?
At $125/month production cost, I need roughly 3 paying customers on the $45/month tier to break even on infrastructure. Or 10 customers on the $12/month tier.
That's a very reachable number. The free tier exists to get people deploying and discovering they need always-on uptime. The conversion event is when someone's app gets real traffic and the 60-second wake time becomes unacceptable.
What I'd tell other founders considering a free tier
- Know your per-user marginal cost. Mine is near-zero because sleeping containers don't cost anything. If yours isn't, a free tier might kill you.
- Auto-sleep is not a compromise — it's the business model. It lets me offer genuine free hosting without losing money on every user.
- Switch to on-demand pricing for everything until you have predictable load. Provisioned capacity is for scale, not for early stage.
- Run shutdown scripts on dev environments. It sounds trivial but $16/day adds up to $480/month.
Happy to share the shutdown scripts or the DynamoDB migration process if anyone's in a similar situation.
60% of Flask deployments on my platform were failing — and it was my fault
I built a container hosting platform. Users connect a GitHub repo, the platform auto-detects the framework, generates a Dockerfile, and deploys. Simple in theory.
Except Flask deploys were failing at a 60% rate. And I couldn't figure out why.
The symptom
Users would push a Flask app. The build would succeed. The container would start. Then the health check would fail, and the deployment would roll back after 15 minutes of waiting. No crash logs. No error messages. Just... silence.
What went wrong
My auto-detection code treated all Python apps the same. It read requirements.txt, saw Python dependencies, and defaulted to port 8000. Every time.
The problem: Flask defaults to port 5000. Gunicorn binds to 5000. But my generated Dockerfile said EXPOSE 8000, and the health check was hitting port 8000. Nobody was listening there.
One line. One wrong port number. 60% failure rate.
It got worse. The same bug existed for frontend frameworks. Angular, React, and Vue apps all got classified as "Node" and assigned port 3000. But those apps build to static files served by nginx on port 80. Same result — health checks hit the wrong port, deployment fails silently.
Why it took weeks to find
Three things made this invisible:
- The build always succeeded (the code compiled fine)
- The container started without errors (gunicorn was running on 5000)
- The health check failure looked like a network issue, not a port issue
I was debugging networking, load balancer configs, security groups. The actual bug was a hardcoded 8000 buried in the framework detection logic.
The fix
I rewrote the detection to actually read what's in the repo:
- requirements.txt has flask? Port 5000.
- requirements.txt has fastapi or uvicorn? Port 8000.
- package.json has angular? That's nginx on port 80, not Node on port 3000.
- Same for React and Vue — static builds, nginx, port 80.
Then I added a fast-fail mechanism. Instead of waiting 15 minutes for a failed deployment to time out, the system now detects sustained unhealthy health checks after 120 seconds and aborts early. Failure time dropped from ~15 minutes to ~3.5 minutes.
The numbers
- Flask failure rate: 60% → near 0%
- Frontend framework failures: similar fix
- Failed deployment wait time: 15 min → 3.5 min
- Root cause: 1 hardcoded port number
- Time to find: ~3 weeks
- Time to fix: 2 days
What I learned
- Auto-detection that works 80% of the time is worse than no auto-detection. The 20% that fails silently destroys trust.
- Health check failures should tell you exactly what went wrong. "Unhealthy" is not a useful error message. I now surface the expected port vs actual port in the error.
- Always test the most popular framework first. Flask is the most common Python framework on my platform. I should have caught this on day one.
If you're building any kind of deployment automation, test the happy path with real repos, not just sample apps you wrote yourself. Your sample app probably has the right port because you wrote the detection logic.
Happy to share more details on the detection architecture or the fast-fail mechanism.
1 Like
Comment
Why I built a bug bounty that rewards any bug — not just security issues
Most bug bounty programs only care about security vulnerabilities. You need to be a security researcher, use specialized tools, and submit through complex platforms like HackerOne. The payouts are big ($100–$10,000+), but the barrier is high.
I run a container hosting platform. My users are mostly indie developers and small teams deploying Docker containers. They're not security researchers — but they find bugs constantly. A dashboard button that doesn't trigger the right action. A deployment that fails with valid config. A log panel showing 0 bytes while the container is actively running.
These bugs matter just as much as security issues. They break trust. They waste time. And the people finding them were getting nothing for reporting them.
So I built a bug bounty program that accepts any valid bug, not just security vulnerabilities.
How it works
Users find a bug during normal platform use. They submit a report through the dashboard with reproduction steps, expected vs actual behavior, and environment details. The QA team reproduces it. If confirmed, the dev team evaluates severity and credits a reward within 7 working days.
What counts as a bug
Five categories qualify: functionality bugs (features not working as intended), security issues (authentication bypass, data exposure), UI/UX bugs (broken layouts, dead buttons), performance problems (timeouts, resource leaks), and integration bugs (GitHub connection failures, webhook issues).
What doesn't count: bugs in the user's own code, feature requests, duplicates, or third-party service issues.
The reward structure
I kept it simple. Critical bugs (security, data exposure) earn a free month on a paid plan. High severity bugs (deployment failures, runtime errors) earn 25+ container hours. Medium bugs (dashboard features broken) earn 10–25 hours. Low severity bugs (typos, minor layout issues) earn 5 hours.
No cash payouts. Platform credits only. This keeps the program sustainable at my scale.
What I learned so far
Report quality matters more than bug severity. A well-documented low-severity bug is more useful than a vague report about something "not working." I added a structured template (summary, reproduction steps, expected vs actual, environment) and the average report quality improved immediately.
The other thing I didn't expect: users who submit bug reports become more engaged with the platform overall. It creates a feedback loop. They find a bug, get rewarded, keep using the platform more carefully, find more issues.
One key distinction
I also run a separate feedback rewards program for general suggestions and UX observations. The difference: bug bounty requires a reproducible software defect and earns higher rewards. Feedback rewards cover "I wish this button was bigger" and earn about 5 hours per submission. Both programs exist because both types of input improve the product.
The numbers
- 5 bug categories accepted
- 4 reward tiers (5 hours to 1 free month)
- 7 working days average review time
- Simple dashboard submission — no external platform needed
If you're building a product and wondering whether to incentivize bug reports beyond security — it's worth trying. The bugs your users find during real work are the ones your QA team is most likely to miss.
Happy to answer questions about how I structured the program or what reward levels make sense at different scales.
1 Like
Comment
I spent 3 weeks building managed database add-ons nobody asked for — here's why I don't regret it
Every container hosting platform I looked at had the same gap: you deploy your app, then you're on your own for the database.
Sign up for RDS. Configure VPC peering. Manage credentials in two different dashboards. Copy-paste connection strings. Deal with separate billing.
I kept watching users hit the same wall. They'd deploy a Flask app in 5 minutes, then spend 30 minutes trying to connect a Postgres instance from somewhere else.
So I built database add-ons directly into the platform.
What I shipped
Four managed databases — PostgreSQL, MySQL, MariaDB, and MongoDB — all running inside the same dashboard as the containers.
The setup flow is intentionally simple:
- Pick a database engine
- Pick a tier (Mini at $24/mo, Standard at $44/mo, Pro at $84/mo)
- Click "Create Database"
- Wait 30-60 seconds
After provisioning, the connection string is automatically injected into the container's environment variables. No manual configuration. No secrets in code.
The browser UI is the real differentiator
Every database gets a built-in web interface. pgAdmin-style for Postgres, phpMyAdmin-style for MySQL/MariaDB, Compass-style for MongoDB.
Here's why this matters more than I expected: it's 11 PM, a user reports a bug, and you need to check one database row. Without a web UI, you're installing pgAdmin locally, configuring the connection, finding the right table. With the web UI, you click one button and run a query in under a minute.
For solo developers and small teams, this removes an entire category of friction.
The hard part wasn't the databases
The databases themselves are managed services under the hood. The hard engineering was the integration layer:
- Auto-injecting connection strings as environment variables
- Making the web interface authenticate through the same dashboard SSO
- Keeping pricing simple — same tiers for all four engines
- Making provisioning feel instant (30-60 seconds, not 5 minutes)
Each of those sounds simple. Each took longer than I expected.
What I learned building this
- Users don't want database choices, they want database defaults. Most people just need Postgres. The decision guide I wrote ("which database should you pick?") gets read, but 70% of add-ons created so far are PostgreSQL.
- A web interface matters more than CLI access. I almost skipped the browser UI to ship faster. Glad I didn't — it's the feature people mention most.
- Integrated beats best-of-breed for small teams. AWS RDS is objectively more powerful. But "one dashboard for containers and data" wins for the indie developer audience.
- Pricing simplicity is a feature. Same price for all four engines. No per-query billing, no IOPS charges, no data transfer fees. Just a flat monthly rate. People appreciate knowing exactly what they'll pay.
The numbers
- 4 database engines supported
- 3 pricing tiers: $24, $44, $84/month
- Provisioning time: 30-60 seconds
- Connection string injection: automatic
- Time to build: ~3 weeks of focused work
Was it worth it?
Too early to tell from a revenue perspective. But from a product completeness standpoint, it fills the biggest gap. "Deploy your app AND your database in one place" is a much stronger pitch than "deploy your app, then figure out your database elsewhere."
If you're building a platform and wondering whether to add adjacent infrastructure features — the answer is yes, if your users keep hitting the same wall.
Happy to share more details on the architecture or pricing decisions.
1 Like
Comment
I'm building a container hosting platform as a solo founder. It runs on AWS — ECS Fargate, DynamoDB, the usual.
Two weeks ago I enabled DynamoDB auto-scaling. It seemed like a best practice. AWS recommends it. Every blog post says do it. So I did.
Three days later I checked my bill and almost choked.
The damage
My dev account went from $13.68/day to $19.52/day (+43%). Production went from $6.69/day to $11.13/day (+66%).
That's an extra ~$300/month I didn't budget for. As a bootstrapped solo founder, that hurts.
What actually happened
DynamoDB auto-scaling was "working" — but my traffic is bursty, not steady. The deployments table was scaling up and down every 5-10 minutes:
82 RCU → 46 → 55 → 28 → 37 → 55 → 28 → 37 → 54 → 45...
50+ scaling events per day. Each time it scales up, you're charged for the peak capacity. Scale-down has a cooldown. So you're paying peak prices for average usage.
But here's the part that really surprised me.
The hidden cost nobody warns you about
Auto-scaling silently created 430+ CloudWatch alarms across my two accounts. About 4 alarms per scaling target. Each alarm costs $0.10/month.
Dev account: 192 alarms = $19.20/month
Production: 232 alarms = $23.20/month
That's $42/month in alarm costs I didn't even know existed. My CloudWatch costs jumped 2,873% overnight.
The fix (embarrassingly simple)
One command per table. Switched all 33 DynamoDB tables from Provisioned to On-Demand:
aws dynamodb update-table --table-name my-table --billing-mode PAY_PER_REQUEST
Then removed all auto-scaling targets. The 430+ alarms disappeared automatically.
Before and after
Monthly AWS bill: $743 → $214 (71% reduction)
DynamoDB cost: ~$14/day → ~$0.03/day
CloudWatch alarms: 430+ → 6
Scaling events per day: 50+ → 0
Dev account: $19/day → $3/day. Production: $11/day → $4/day.
Total monthly savings: $529.
What I learned
1. Auto-scaling isn't free. The scaling itself costs money and it silently creates hundreds of CloudWatch alarms. Nobody mentions this in the "how to set up DynamoDB" tutorials.
2. On-demand wins for bursty workloads. If your traffic is unpredictable (i.e., you're a startup), on-demand is almost always cheaper than provisioned + auto-scaling.
3. Check your CloudWatch alarm count right now.
Seriously.
Run this:
aws cloudwatch describe-alarms --query 'MetricAlarms | length'
You might be surprised.
Bonus: shutdown scripts
I also wrote scripts that scale my dev environment to zero when I'm not working — ECS services to 0, EC2 instances stopped. Takes 2-3 minutes to bring back up. Dev environment now costs ~$3/day when idle.
If you're running DynamoDB with auto-scaling and your workload is bursty, check your costs. You might be bleeding money the same way I was.
Happy to share the scripts or answer questions about the specifics.
1 Like
1 Comment
1 Comment
-
1great writeup — the 430 auto-created CloudWatch alarms thing is exactly the kind of silent leak most people never see on their bill. I built a free browser-only scanner that reads your cost csv locally (no aws creds) and spits a safe-delete list — found a bunch of these in similar setups. getcloudsaver.com if useful. either way, on-demand dynamodb tip is gold.
I spent way too many hours in my career dealing with SSL certificates. Generating them, renewing them, debugging "certificate expired" alerts at 2 AM.
When I built SnapDeploy, I made a decision: custom domains should just work. Add your domain, point DNS, done. No certificate management.
The Old Way
Setting up a custom domain for a containerized app typically means:
Configure your ingress/load balancer
Set up DNS records (and hope you got them right)
Generate SSL certificates (Let's Encrypt? ACM? Something else?)
Configure automatic renewal (cert-manager? Cron job?)
Debug why HTTPS isn't working
Get paged when certificates expire anyway
For a simple container deployment, that's ridiculous.
The Simple Way
Here's what custom domains look like on SnapDeploy:
Click "Add Domain"
Enter
api.yourcompany.comGet an IP address
Add one A record at your DNS provider
Wait 5-10 minutes
That's it. SSL is automatic. Renewal is automatic. No infrastructure to manage.
Why A Records?
Most platforms make you use CNAME records, which don't work on root domains (yourcompany.com). You end up needing "CNAME flattening" or workarounds.
A records just work. Root domain? Works. Subdomain? Works. Every DNS provider supports them.
Real Numbers
PlanCustom DomainsFree0Hobby0Starter2Pro5BusinessUnlimited
Most indie projects need 1-2 domains. The Starter plan covers that.
The Technical Side (If You Care)
Behind the scenes:
Caddy proxy handles incoming traffic
Let's Encrypt provides free certificates
Automatic renewal before expiration
Zero downtime during certificate updates
But you don't need to know any of this. Just add your domain.
Conclusion
Developers should spend time building products, not managing certificates.
If you're tired of SSL complexity, give SnapDeploy a try. Your next custom domain setup should take 5 minutes, not 5 hours.
Question: What's your worst SSL certificate horror story?
1 Like
Comment
Every developer hosting side projects has hit this wall:
You deploy your portfolio, your demo app, your MVP. It works great. Then traffic dies down for a few hours, the platform puts your container to sleep, and the next visitor gets... nothing. A blank screen. A timeout. A broken first impression.
I kept hearing about this problem from developers using Render, Railway, and other platforms. The usual advice? "Just pay for always-on containers."
But that's $20-30/month per container for apps that get maybe 10 visits a day. For a portfolio? For a demo? That math doesn't work.
The Real Problem
Cold starts happen because platforms need to be resource-efficient. When your app isn't getting traffic, they shut it down. Makes sense for them.
But when traffic comes back, starting a container takes 30-60 seconds. During that time, your visitor sees:
A blank screen
A timeout error
Nothing at all
They refresh once, assume it's broken, and leave. For a portfolio site, that might be a recruiter. For a demo, that might be a potential customer.
The Solution I Built
Instead of trying to eliminate cold starts (expensive) or ignoring them (bad UX), I asked: what if we just made them visible?
The idea:
Intercept requests at the edge before they hit the sleeping container
If the container is asleep, show a "waking up" page
Trigger the container to start
Auto-refresh when it's ready
Users don't mind waiting 15 seconds if they understand what's happening. They DO mind a timeout error.
How It Works
I built this into SnapDeploy using Cloudflare Workers:
User clicks link → Cloudflare intercepts → Container asleep? ↓ YES → Show wake page NO → Route normally
The wake page is simple:
SnapDeploy branding
"Your app is waking up..."
Progress indicator
Auto-refresh when ready
The container still takes 10-30 seconds to start, but the user experience is completely different.
Real Results
Before:
30-60 second blank screen
Users assume site is broken
Lost opportunities
After:
Instant feedback
Clear communication
Users wait for the actual app
Same infrastructure cost. Night and day difference in perception.
Who This Is For
This pattern works great for:
Personal portfolios - Make a good impression even on a free tier
Side projects - Don't pay $20/month for something you're testing
MVPs - Validate ideas without burning credits
Internal tools - Admin dashboards that only get used occasionally
If you need instant response times for production APIs, you still need always-on containers. But for everything else? This is the answer.
Try It
I've made this the default behavior on SnapDeploy. Deploy any container, let it sleep, visit it—you'll see the wake page in action.
No more cold start anxiety. No more paying for idle containers.
Question for the community: How are you handling cold starts for your side projects?
1 Like
Comment
Everyone building side projects hits this problem:
You share your app link. Someone clicks it. They stare at a blank screen for 30 seconds. They leave.
That's a cold start. Your container was asleep, and waking it up takes forever.
The obvious "solutions"
1. Ping services - Keep your container awake by pinging it every 14 minutes. Gaming the system. Burns through your free tier hours.
2. Pay more - Upgrade to always-on. $7-20/month per container. Overkill for a portfolio site that gets 10 visitors/month.
3. Accept it - Let users wait. They'll think your app is broken.
What I built instead
Used Cloudflare Workers as a "waiting room" at the edge.
When someone visits and the container is asleep:
Cloudflare instantly serves a "waking up" page (no delay)
Container starts in background
Page auto-refreshes when ready
The container still takes 15-20 seconds to wake. But users see activity immediately instead of a blank screen.
Psychology matters. People will wait for something they can see is loading. They won't wait for nothing.
The numbers
MetricBeforeAfterTime to first byte30+ seconds<100msPerceived waitInfinite (blank)15-20 sec with feedbackBounce rateHighMuch lower
Cost: $0/month
Cloudflare Workers free tier handles this easily. The container still sleeps, still saves money. Users just get a better experience.
Built this into SnapDeploy as a default feature. Every container gets it automatically - no setup required.
What UX problems have you solved with clever architecture instead of throwing money at it?
1 Like
Comment
After shipping SnapDeploy's custom domain feature last month, I got asked: "Why A records? Everyone uses CNAME."
Here's the thing - CNAME records have a dirty secret: they don't work on root domains.
Try pointing example.com (not www.example.com) to a CNAME. Your DNS provider will either reject it or do "CNAME flattening" behind the scenes. It's messy.
The Problem I Kept Seeing
Users would sign up, deploy their container, then message me:
"I want to use mydomain.com but your docs say CNAME and my DNS won't let me"
This happened at least once a week.
The Fix: A Records
Switched the entire system to use A records instead:
Works on root domains (
example.com) ✓Works on subdomains (
api.example.com) ✓No CNAME flattening weirdness ✓
Faster DNS resolution ✓
Setup is now dead simple:
Add domain in dashboard
Copy the IP address
Add A record in your DNS
Wait 10 min for SSL
Quick Comparison
PlatformRecord TypeRoot Domain?SnapDeployA RecordYesRenderCNAMENeeds workaroundRailwayCNAMENeeds flatteningHerokuCNAMENo
Lesson Learned
Sometimes the "standard" way isn't the best way. CNAME is everywhere because that's what tutorials copy from each other. But A records solve the root domain problem that frustrates users.
Small infrastructure decisions = big UX impact.
Custom domains available on Starter plan ($39/mo) and up. Free tier gets a subdomain at yourapp.snapdeploy.dev.
What infrastructure decisions have you made that seemed small but had outsized impact?
1 Like
Comment
This week I focused on organic growth instead of spending on ads.
Added SnapDeploy to:
• AlternativeTo (DoFollow, DA ~70)
• Dev.to (DoFollow, DA ~85)
• Hashnode (DoFollow, DA ~80)
• Indie Hackers (here!)
Total cost: $0
Time spent: ~8 hours
For bootstrapped founders, backlink strategy beats paid ads early on. Google needs time to index, but it compounds.
What's working for you?
Paid ads or organic?
1 Like
Comment
About
After 15 years as an AWS architect working with 200+ developers, I kept hearing the same frustration: "Why is deploying a simple app so hard?" So I built the solution I wished existed.


1 Comment