Your First Real AWS Project, End to End (Bill: $0.00)
This is the post the whole series has been walking toward: you and me, building a real, working AWS project end to end — a link shortener you actually own, live on the internet, handling real clicks — using the exact services the series taught: S3, Lambda, API Gateway, and DynamoDB. And here is the fact that makes it worth your Saturday: the finished app costs $0.00 a month. Not trial credits that expire, not a 12-month teaser — AWS’s always-free tier covers every piece of it permanently at hobby scale, and when traffic grows, a million clicks costs about a dollar. The quiet scandal is why so few people know this: most AWS tutorials route beginners through the expensive doors — the API type that bills 3.5x more, the always-on servers, the $32-a-month networking add-ons — not out of malice, but out of habit. We’ll take the cheap doors on purpose, name every trap as we pass it, and end with a bill you can frame. Build time: about an hour. Servers involved: zero.
Jake owes this project to his cousin’s tutoring class. She had printed two hundred posters with a QR code on them — the code pointed at a free link-shortener service, which pointed at her enrollment form. Eight months later, parents started calling: the QR code now opened a page of ads, with her form buried behind a "continue" button that looked like a trap. The free service had changed its business model, as free services do, and every poster in town now advertised someone else’s ads. She couldn’t fix the posters. She couldn’t fix the shortener — she didn’t own it. Jake rebuilt the whole thing on AWS in one evening: a short domain she controls, redirects she controls, and a running bill of exactly zero. The new posters carry a link that will still work when her students have students. That is the real argument for this project — not the resume line, though it earns that too: links you own behave; links you borrow eventually don’t.
Ethan: "Everyone assumes going online means renting a shop — lease, staff, lights on all night, whether customers come or not. That’s the server model, and it’s why people expect a monthly bill. What we’re building is a vending machine: it stands there costing nothing, wakes up for exactly one transaction when someone presses a button, and goes back to costing nothing. And at your volume, the mall has a standing policy of waiving small machines’ fees entirely. That’s not a promotion that expires — it’s the posted policy. The trick, and it’s the whole trick, is refusing every upsell that tries to turn your vending machine back into a shop lease."
What you’ll have when you’re done
Four pieces, each one a stop this series already made, each doing the one job it was built for. A tiny web page hosted on S3 where you paste a long URL. It calls an API Gateway address — your app’s front door. The door hands the request to a Lambda function — forty lines of Python, the entire brain, running only in the instant it’s needed. The brain writes to a DynamoDB table — the notebook that remembers xK4b2n → your-long-url forever. When anyone clicks the short link, the same door and brain look the code up and bounce the visitor to the real destination before they’ve finished blinking.
Notice what is not in that list: no server, no operating system, no disk to manage, nothing that is "on" between requests, nothing to patch on the second Tuesday of the month. When zero people use your app, zero computers are running it. That single idea — and the pay-per-use bill it produces — is the most valuable thing this build teaches, and it’s why we saved it for the graduation exercise.
Why a link shortener, of all things
Because it is the smallest project that is still real. It has a write path (making a link), a read path (clicking one), a database, an API, and a user — the same anatomy as a booking system, a to-do app, or the backend of a mobile game. Learn to wire these four pieces once and you have learned the shape of most modern applications; everything bigger is this, repeated with more tables and more routes.
And unlike a practice todo-list that dies the day the tutorial ends, this one earns its keep. QR codes for a menu, a wedding invite, a class handout; clean short links under your own name instead of a stranger’s domain; click counts you can actually see (we store them from day one — that’s a two-line bonus you’ll meet inside the code). Jake’s cousin is the cautionary tale for the alternative: free shorteners have been shutting down, expiring old links, and quietly wrapping them in ads for a decade. Yours will do none of those things, because yours answers to you.
Before anything else: the $1 tripwire
House rule of this series, and we’re not skipping it on graduation day: before creating anything that could ever cost money, create the thing that tells you it’s costing money. In the console, search for Budgets, create a monthly cost budget of $1, and point the alert at an email you actually read. Two minutes. Our AWS billing guide walks through every click and explains the horror stories it prevents — the short version is that every "AWS charged me $700" story on the internet shares one detail: no alarm was set.
While you’re in a setting-up mood, two more one-time notes. First, do this build signed in as your everyday admin user, not the root account — if the phrase "IAM user" is new, the IAM stop exists for exactly this moment. Second, pick region us-east-1 (N. Virginia) from the dropdown at the console’s top right, and stay there for the whole build — every price in this post is quoted from it, and half of all "my thing disappeared!" beginner panics are just the console quietly sitting in a different region. If you take one superstition from this series, take that one.
A word on the newer free plans, because AWS changed them and old tutorials haven’t caught up: accounts created since mid-2025 start with $100 in credits, plus up to $100 more for completing onboarding activities, on a free plan that runs six months. That’s a nice cushion, but this build barely touches it — we’re aiming at the always-free tier, the separate list of allowances (Lambda’s million requests a month, DynamoDB’s 25 GB, and friends) that never expires on any plan. Credits are a welcome gift; always-free is the load-bearing wall.
Step 1 — DynamoDB: the notebook (5 minutes)
We start with the database because everything else points at it. In the console, open DynamoDB → Create table. Table name: links. Partition key: code, type String. That’s the whole schema — as the DynamoDB stop explained, you don’t declare columns up front; each item carries whatever fields it likes, and ours will carry three: the code, the long URL, and a click counter.
Now the first cheap-door moment of the build, and it hides under Customize settings: the console’s default capacity mode is on-demand, which bills per request — $0.625 per million writes, $0.125 per million reads in us-east-1. Tiny numbers, and on-demand is a fine default in general. But the always-free tier gives every account 25 read units and 25 write units of provisioned capacity, free forever — and 25 units sustains more traffic than a personal shortener will ever see. So: choose Provisioned, set both read and write capacity to 5 with auto scaling off, and your database’s line on the bill becomes a permanent $0.00. One dropdown, one deliberate choice the default wouldn’t have made for you. Create the table and step one is done.
Step 2 — Lambda: the entire app is 40 lines (15 minutes)
Open Lambda → Create function → Author from scratch. Name it shortener, pick the newest Python runtime in the list, leave everything else alone, and create. You now own a function that runs only when called and bills by the millisecond — the vending machine itself, as the Lambda stop promised. Replace the starter code in the editor with this, then press Deploy:
import json, string, random, boto3
table = boto3.resource("dynamodb").Table("links")
def lambda_handler(event, context):
method = event["requestContext"]["http"]["method"]
path = event["rawPath"]
# Making a new short link: POST /links with {"url": "https://..."}
if method == "POST" and path == "/links":
body = json.loads(event.get("body") or "{}")
url = (body.get("url") or "").strip()
if not url.startswith(("http://", "https://")):
return reply(400, {"error": "Send a full URL starting with http:// or https://"})
code = "".join(random.choices(string.ascii_letters + string.digits, k=6))
table.put_item(
Item={"code": code, "url": url, "clicks": 0},
ConditionExpression="attribute_not_exists(code)",
)
domain = event["requestContext"]["domainName"]
return reply(200, {"short": "https://" + domain + "/" + code})
# Clicking a short link: GET /anything looks it up and redirects
if method == "GET":
code = path.strip("/")
item = table.get_item(Key={"code": code}).get("Item")
if not item:
return reply(404, {"error": "That short link does not exist."})
table.update_item(
Key={"code": code},
UpdateExpression="ADD clicks :one",
ExpressionAttributeValues={":one": 1},
)
return {"statusCode": 301, "headers": {"Location": item["url"]}}
return reply(404, {"error": "Route not found"})
def reply(status, data):
return {
"statusCode": status,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(data),
}
Read it once, even if Python isn’t your language — it reads like the sentence it is. A POST to /links checks the URL looks like a URL, invents a six-character code, and writes one item to the table (the ConditionExpression is the polite way of saying "and refuse the one-in-56-billion chance this code already exists"). A GET looks the code up, adds one to its click counter — there’s your analytics, two lines, no product to buy — and answers with status 301 and a Location header, which is the entire mechanism of every redirect on the internet. No framework, no configuration files. This is the whole backend.
One permission errand before it can run: the function’s auto-created role is allowed to write logs and nothing else — AWS’s deny-by-default posture doing its job. On the function’s Configuration → Permissions tab, click the role name (it opens IAM), then Add permissions → Attach policies, and attach AmazonDynamoDBFullAccess. That’s the blunt tutorial-grade grant — honest label — and the IAM post shows how you’d later tighten it to "this table, these actions" like a production adult. For today: attach, move on.
Step 3 — API Gateway: the front door (10 minutes, one big trap)
Your function exists, but the internet can’t reach it — Lambda has no address of its own. API Gateway is the address. And right here sits the single most expensive wrong click available to a beginner, the one the API Gateway stop was practically written to prevent: the console offers you a REST API (the one nearly every older tutorial builds, at $3.50 per million requests) and an HTTP API (newer, simpler, faster to set up — $1.00 per million). Same job for an app like ours, 3.5x price difference, and the expensive one has the more inviting name. Choose HTTP API. Every time. If a tutorial you meet later starts with "create a REST API," check its publication date and hold onto your wallet.
- Open API Gateway → Create API → HTTP API → Build.
- Add integration → Lambda → pick
shortener. Name the APIshortener-api. - On the routes screen, create two routes:
POST /linksandGET /{code}— the curly braces make the second one a catch-all that hands whatever code the visitor clicked to your function. Attach the same Lambda integration to both. - Accept the default
$defaultstage with auto-deploy on, and create. There is no separate "deploy" ceremony — another chore the HTTP flavor simply deleted.
The API’s details page now shows an Invoke URL like https://ab12cd34ef.execute-api.us-east-1.amazonaws.com. Copy it somewhere — that string is your app’s public address, and the next step makes it do something wonderful.
The first live test — the part where it becomes real
Open a terminal — PowerShell on Windows works fine, since curl ships with it — and send your app its first real request, swapping in your own invoke URL:
curl -X POST "https://ab12cd34ef.execute-api.us-east-1.amazonaws.com/links" -H "Content-Type: application/json" -d "{\"url\": \"https://www.logeshwaran.org\"}"
Back comes something like {"short": "https://ab12cd34ef.execute-api.us-east-1.amazonaws.com/xK4b2n"}. Now paste that short URL into a browser. It redirects. Stop and let that land properly: a database you created, behind a function you wrote, behind an address the world can reach, just served a real request — and every component of it materialized in the last half hour without a single server existing anywhere in the story. Go look at the item sitting in your DynamoDB table (Explore table items) — code, URL, and a click count that just became 1. If you got goosebumps, you’re doing this exactly right; if you got an error instead, skip ahead two sections — you’ve almost certainly met the wall we all meet, and it has a name and a two-minute fix.
Step 4 — S3: a face for it (15 minutes)
Curl is for builders; your cousin needs a page with a box and a button. Save this as index.html on your desktop, putting your own invoke URL into the first line of the script:
<!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My link shortener</title>
<body style="font-family:system-ui;max-width:520px;margin:60px auto;padding:0 16px;">
<h1>Shorten a link</h1>
<input id="url" type="url" placeholder="https://paste-something-long-here..."
style="width:100%;padding:12px;font-size:16px;box-sizing:border-box;">
<button onclick="go()" style="margin-top:12px;padding:12px 24px;font-size:16px;">Shorten</button>
<p id="out" style="font-size:18px;word-break:break-all;"></p>
<script>
const API = "https://ab12cd34ef.execute-api.us-east-1.amazonaws.com";
async function go() {
const r = await fetch(API + "/links", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({url: document.getElementById("url").value})
});
const data = await r.json();
document.getElementById("out").textContent = data.short || data.error;
}
</script>
</body>
Now give it a home. In S3 → Create bucket, pick a globally unique name (bucket names share one worldwide namespace — links-yourname-2026 style works). During creation, uncheck "Block all public access" and acknowledge the warning — this bucket’s entire purpose is to be read by the public, and it will hold exactly one webpage, nothing else, which is the honest answer to the console’s worried tone. Upload index.html. Then, under the bucket’s Properties → Static website hosting, enable it with index.html as the index document.
One more gate: unchecking the block only permits public access; it doesn’t grant it. Under Permissions → Bucket policy, paste the standard public-read policy (swap in your bucket name):
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::links-yourname-2026/*"
}]
}
If S3 answers anything here with 403 Access Denied, you are standing in the most-visited error in this entire series and we have a whole post untangling S3’s four permission layers — it will have you moving again in minutes. Once hosting is on, the Properties tab shows your website endpoint. Open it: there’s your page, served from the same storage service the S3 stop introduced — for fractions of a cent, to any number of visitors.
The CORS wall — where every single builder gets stuck once
Now press your shiny Shorten button and enjoy the rite of passage: nothing happens. The browser console (F12) mutters something about "blocked by CORS policy." Curl worked; the webpage doesn’t. If your day held one small heartbreak, this is probably it — so first, the reassurance: your app is fine, this failure is universal, and it is a security feature behaving exactly as designed. Browsers refuse to let a page on one domain (your S3 site) quietly send requests to a different domain (your API) unless the API itself declares "that origin is welcome here." Without that handshake, any random webpage you visited could make requests to your bank using your cookies. CORS is the internet’s bouncer, and today you’re on the wrong side of the rope for a well-intentioned reason.
Getting on the list takes two minutes: in your API’s settings, open CORS, and configure — Access-Control-Allow-Origins: your S3 website endpoint (paste the exact address, no trailing slash; * also works for a toy and you can tighten it later), Allow-Methods: POST, GET, Allow-Headers: content-type. Save, reload your page, press the button again — and watch a short link appear in the page like it was never a problem. You have now debugged the same wall that has humbled every cloud developer alive. It only happens to you once; from now on, "works in curl, fails in browser" will make you say "CORS" before the error finishes printing.
The bill, honestly: four traffic levels, priced
The hub promised this project "bill included," so here it is — us-east-1 prices as of August 2026, with the always-free allowances applied the way they genuinely apply (they never expire, on any plan; only the Lambda pool is shared with your other functions):
| Clicks this month | API Gateway (HTTP, $1.00/M) | Lambda | DynamoDB (provisioned, in free 25 units) | S3 page | Total |
|---|---|---|---|---|---|
| Family & friends (hundreds) | $0.00 | $0 (free 1M requests) | $0.00 | ~$0.00 | $0.00 |
| 10,000 | $0.01 | $0 | $0.00 | ~$0.01 | ~$0.02 |
| 1,000,000 | $1.00 | $0 (still inside the free million) | $0.00 (avg ~0.4 requests/sec — comfortable) | ~$0.02 | ~$1.02 |
| 10,000,000 | $10.00 | ~$1.80 (9M billable requests; compute still under the free 400K GB-seconds) | $0 if traffic is steady; spiky bursts may throttle at 25 units — switching to on-demand adds ~$7.50 | ~$0.05 | ~$12–19 |
Read the last column twice, because it rearranges how you think about hosting: a million real visitors costs about a dollar, and ten million costs less than two movie tickets. Then notice what protects those numbers — every one of them assumes the choices this post made on purpose: HTTP API instead of REST (or that $10 row reads $35), provisioned DynamoDB inside the free units, and no always-on anything. The services that ambush beginners — the NAT Gateway billing $32.85 a month while idle from the VPC stop, the forgotten EC2 instance humming for nothing — are ambushes precisely because they cost money while nothing happens. Nothing in this build can do that. That’s not luck; that’s architecture.
Where every series stop plugged in (and the ones we didn’t need)
This build was the series in miniature — here’s the map, including the stops whose absence teaches something:
| Role in this build | Service | The stop that explains it |
|---|---|---|
| The tripwire before anything | Budgets | Billing, free tier & budgets |
| Who’s allowed to do what | IAM | IAM in plain English |
| The notebook | DynamoDB | DynamoDB introduction |
| The brain | Lambda | Lambda & serverless |
| The front door | API Gateway | API Gateway (and the 3.5x trap) |
| The face | S3 | S3 cloud storage + the 403 fixer |
| Not needed: servers & their disks | EC2, EBS | EC2 & EBS — your first real project shipped with zero of either |
| Not needed: a network to manage | VPC | VPC — your default VPC sat there, free, untouched, exactly as that post said it would |
| Not needed (yet): a relational database | RDS | RDS — the day your data grows joins and reports, this is the door |
| The first extensions: messages & alerts | SQS, SNS | SQS & SNS — see the weekend list below |
| The horizon: AI on your data | SageMaker, Bedrock | SageMaker & Bedrock — the click data you’re now collecting is exactly the kind of thing they eat |
Make it better this weekend
The build is done, but projects are for growing. Each of these is an evening, and each teaches one new muscle:
- Show the click counts. They’re already in the table (that
ADD clicks :oneline has been counting since your first test). Add aGET /stats/{code}route that returns the item as JSON — congratulations, you’ve built an analytics API. - Custom codes. Let the POST body carry an optional
codefield so/diwali-menubeats/xK4b2n. TheConditionExpressionalready protects you from collisions — notice you accidentally engineered that in advance. - Self-destructing links. DynamoDB has a built-in, free TTL feature: store an expiry timestamp in each item, switch TTL on for that field, and the table deletes expired links on its own. No cleanup script, no scheduled job.
- An email when someone uses your shortener. One SNS topic, one subscription, one
publishcall in the Lambda — the SNS stop is the manual. - A real domain. The invoke URL works but
ab12cd34ef.execute-api...is nobody’s idea of a short link — which is exactly why it’s the series’ next promise. See below.
Tear it down — or keep it (both answers are $0)
A habit worth building on your very first project: know how to leave. If this was a learning exercise and you’re done, deletion takes five minutes — and the order doesn’t matter, since nothing depends on anything being deleted first: delete the API in API Gateway, the function in Lambda (its IAM role survives; delete that in IAM too if you’re being thorough), the links table in DynamoDB, and the bucket in S3 (empty it first — S3 refuses to delete buckets with contents, a stubbornness you’ll come to appreciate). Leave the $1 budget alarm alive forever; it costs nothing and guards everything you build after this.
But here’s the genuinely unusual thing, the reason this project makes such a good first one: you don’t have to choose. Keeping it running costs the same as deleting it — zero — because nothing in it bills while idle. There is no meter to stop. Most tutorials end with "remember to shut everything down or you’ll be charged"; this one ends with "leave it running for your cousin’s posters if you like." That difference is serverless architecture, summarized in one sentence.
Honest aside: what this project cannot teach you
Balance, as always. One build does not make you a cloud engineer, and it’s worth being precise about the gaps. You clicked the console instead of writing infrastructure-as-code — the right call for a first build, and a thing to grow out of, because clicked infrastructure can’t be reviewed, repeated, or rebuilt after a mistake. You granted a tutorial-grade permission (AmazonDynamoDBFullAccess) that a production reviewer would bounce. Your API has no authentication — anyone who finds the endpoint can mint links on your dime, which at $1 per million is a threat you can afford to laugh at today and must not laugh at on a real product. And you haven’t touched the operational half of the craft — the logs, metrics, and alarms that tell you why something broke at 2 a.m. (your Lambda has been writing logs to CloudWatch this whole time, by the way — go peek; it’s a good habit’s first day).
But don’t let the gap list shrink what happened here, because the thing you now have is rarer than any certification bullet: a working mental model. You know what a managed database feels like, what deny-by-default feels like, what pay-per-use feels like when the bill arrives and it’s a dollar. Cloud interviews, cloud docs, and cloud arguments all get easier from the far side of one real build — and you’re on the far side now. The series’ next promise picks up the loosest thread left hanging: that ugly execute-api address. Next stop: putting your project behind your own domain with HTTPS — CloudFront and Route 53 in plain English, priced honestly like always.
FAQ — your first AWS project, answered straight
What is a good first AWS project for a beginner?
A serverless URL shortener: S3 for the page, API Gateway for the front door, Lambda for the logic, DynamoDB for storage. It has every part of a real application, costs $0.00 a month at personal scale, and finishes in about an hour.
How much does it cost to run a URL shortener on AWS?
At hobby traffic, $0.00 — the always-free tier covers Lambda, DynamoDB (provisioned within 25 free units), and effectively S3. At scale, about $1 per million clicks, almost all of it API Gateway’s $1.00/million HTTP API rate.
Do I need to know programming to build this?
Paste-level Python is enough — the entire backend is one 40-line function, and this post explains what each part does. If you can read an if-statement, you can maintain it.
Do I need an EC2 server for this project?
No — and that’s the point. Lambda runs the code only when a request arrives, so nothing is running (or billing) between clicks. Your first real project ships with zero servers.
Is the AWS free tier actually free in 2026?
Two separate things: new accounts get a free plan with $100 in credits (up to $200 with onboarding activities) for six months, and a list of always-free allowances — Lambda’s 1M requests/month, DynamoDB’s 25 GB and 25 provisioned units — that never expires on any plan. This build lives on the always-free list.
What happens to my project when the 6-month free plan ends?
Nothing, for this build — it runs on always-free allowances, not the expiring credits. The credits are a cushion for experiments; the shortener never needed them.
Should the DynamoDB table be on-demand or provisioned?
For this project, provisioned at 5 read/5 write units — inside the 25 always-free units, so it’s permanently $0. On-demand is the better default for spiky or unknown workloads and still only costs $0.625 per million writes and $0.125 per million reads in us-east-1.
Why an HTTP API instead of a REST API in API Gateway?
Same job for an app like this, 3.5x price difference: HTTP APIs cost $1.00 per million requests, REST APIs $3.50. REST adds features (API keys, usage plans, request validation) that a first project doesn’t need. Older tutorials default to REST because HTTP APIs are newer.
Why DynamoDB instead of MySQL or RDS?
The workload is one-key-in, one-item-out — DynamoDB’s perfect shape — and RDS’s smallest always-on instance costs real money every hour while DynamoDB here costs nothing. When your data grows relationships and reporting needs, that’s the honest moment to meet RDS.
How do I make sure AWS never surprises me with a bill?
Set a $1 budget alarm before building anything; prefer services that bill per-request over services that bill per-hour; and never create a NAT Gateway, the classic $32.85/month idle trap. This build follows all three rules by design.
Can I use my own domain instead of the execute-api address?
Yes — API Gateway supports custom domains, and pairing the project with CloudFront and Route 53 gives you a real short domain with HTTPS. That is the series’ next post, in the usual plain English with the usual honest prices.
What is CORS and why did my page fail when curl worked?
Browsers block a page on one domain from calling an API on another unless the API explicitly allows that origin — a security feature, not a bug. Fix it in the API’s CORS settings: allow your S3 site’s origin, methods POST and GET, header content-type. Command-line tools like curl aren’t browsers, so they never hit the wall.
Is making my S3 bucket public dangerous?
For this bucket, no — it holds one webpage whose whole purpose is being publicly readable, the same as any website. The rule that matters: never make a bucket public that holds anything you didn’t intend to publish, and keep the public one dedicated to the site.
Can this little app handle real traffic?
Comfortably. Every piece scales automatically — a million clicks a month averages under half a request per second, a bad joke for these services. The first thing to revisit at genuinely large scale is the 25 free DynamoDB units during traffic spikes.
How do I delete everything when I’m done?
Delete the API in API Gateway, the function in Lambda (plus its role in IAM), the table in DynamoDB, and the emptied bucket in S3 — five minutes, any order. Keep the $1 budget alarm forever.
Which AWS region should I build in?
us-east-1 (N. Virginia) for this tutorial — it’s where the quoted prices apply and where most guides assume you are. Whatever you pick, stay consistent: resources live in one region, and the console showing a different one is the top cause of "my table vanished" panic.
Does this project look good on a resume?
A deployed project with a live URL beats a certificate-only resume line in most screenings — it proves you’ve touched the console, IAM, and a real bill. Pair it with the click-stats extension and you can talk about data, too.
What should I build after this?
Grow this one first — click stats, custom codes, TTL expiry, an SNS email — then rebuild it with infrastructure-as-code as project two. The same four services also make a guestbook, a poll, or a portfolio contact form; the shape you just learned is the shape of all of them.
Revision note. Written August 26, 2026 — the fifteenth stop in the series and the keeping of its longest-standing promise: the hub said your first real project would wire S3, Lambda, API Gateway, and DynamoDB into one small thing that actually runs, bill included, and this is that page. All prices checked against AWS’s own pricing pages the day of writing (us-east-1; AWS cuts these more often than it raises them, so drift will likely be in your favor). The console’s buttons will inevitably shuffle over the years — if a screen no longer matches a sentence here, the concepts hold and the contact page reaches me for fixes. And if you build it and the CORS wall or a 403 eats your evening anyway: that was every one of us, the first time. The difference between someone who "knows AWS" and someone who doesn’t is mostly a stack of small walls like that one, hit once each. You just hit yours. Welcome to the far side — and bring the posters; the links are yours now.If you ask me whether i can build a cool business like the ones you already it, the choice is always yours, like i always say😼! and age? Until death hits us, reset of our financial situation is forever possible, the question is whether you want or don't want! Enough motivation, see u on next post.
