Deploy a Portfolio Site to AWS S3
Use Git, GitHub, and AWS CLI to deploy a portfolio website to S3.
Introduction
30 Second Summary
Every file you save overwrites what came before. Developers use a system called version control to track every change, undo mistakes, and collaborate without losing work.
In this project, you will build a personal portfolio site with HTML and CSS. You will manage it with Git and deploy it live to AWS S3.
What You'll Build
A personal portfolio website managed with Git version control, hosted publicly on AWS S3, and backed by a real commit history on GitHub.
By the end of this project, you'll have:
- A Git repository on GitHub with branches, a pull request, and merge history.
- An HTML/CSS portfolio page with an About Me section and a Projects section.
- A live website URL on AWS S3, deployed from your terminal with the AWS CLI.
- Secret Mission: simulate and resolve a merge conflict to level up your Git confidence.
Are there any prerequisites?
This project assumes you have an AWS account with the AWS CLI already configured, a GitHub account, VS Code installed, and Git set up on your machine. Basic familiarity with terminal commands is helpful.
Before We Start
Before We Start...
Verify Your Tools and Configure Git
Before writing any code, you need to confirm that every tool in your toolchain is installed and talking to the right accounts. This project depends on Git, the AWS CLI, and GitHub all working together.
In this step, you will open your terminal and run a few quick checks. You will also set up your Git identity so every commit you make is properly labeled.
In this step, get ready to:
- Verify that Git and the AWS CLI are installed and configured.
- Set your Git username and email for commits.
- Confirm your GitHub authentication method.
Open VS Code and verify your tools
Each tool needs a quick version check to make sure it is available in your terminal. You will check Git, the AWS CLI, and your AWS account configuration.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Visual Studio Code and press Enter to open it.
- Open the integrated terminal by pressing Ctrl+` (backtick). You can also click Terminal in the top menu bar, then click New Terminal.
A terminal panel opens at the bottom of VS Code. This is where you will run all the commands in this project.
- Verify Git is installed by running this command:
git --version
✔️ I see a version number
You should see something like git version 2.x.x. Git is ready to go.
ⓧ Command not found
Git is not installed yet. Follow the steps below for your operating system.
macOS
- Install the Xcode Command Line Tools (which includes Git) by running:
xcode-select --install
- A dialog box will appear asking you to install the tools. Click Install and wait for it to finish.
- Run git --version again to confirm the install worked.
Windows
- Install Git using winget by running this command in PowerShell:
winget install --id Git.Git -e --source winget
- Close and reopen your VS Code terminal after the installation completes.
- Run git --version again to confirm the install worked.
- Verify the AWS CLI is installed by running this command:
aws --version
✔️ I see a version number
You should see output starting with something like aws-cli/2.x.x. The AWS CLI is ready.
ⓧ Command not found
The AWS CLI is not installed yet. Visit the official AWS CLI install guide and follow the instructions for your operating system.
- After installing, close and reopen your VS Code terminal.
- Run aws --version again to confirm it installed correctly.
- Then run aws configure to set your Access Key ID, Secret Access Key, default region, and output format.
Having the AWS CLI installed is one thing. You also need to confirm it is connected to your AWS account.
- Confirm your AWS CLI configuration by running this command:
aws sts get-caller-identity
What does this command do?
This command asks AWS "who am I?" using the credentials stored on your machine. If your CLI is configured correctly, it returns your Account ID, User ID, and ARN.
✔️ I see my account details
You should see a JSON response containing Account, UserId, and Arn fields. Your AWS CLI is properly connected to your account.
ⓧ I see an error
This usually means the AWS CLI has not been configured with your credentials yet.
- Run the following command to set up your credentials:
aws configure
- The command will prompt you for four values: your AWS Access Key ID, Secret Access Key, default region (e.g. us-east-1), and output format (enter json).
- After entering all four values, run aws sts get-caller-identity again to confirm it works.
Still seeing an error?
Double-check that your Access Key ID and Secret Access Key are correct. You can generate new keys in the AWS Management Console under IAM > Users > your user > Security credentials.
Help me troubleshoot my AWS CLI configuration
Configure your Git identity
Every Git commit records who made the change. Git uses a global username and email to stamp this information on each commit you create.
- Set your Git username and email by running these commands:
git config --global user.name "[[YOURNAME="Your Name"]]"
git config --global user.email "[[YOUREMAIL="your-email@example.com"]]"
Why do I need a Git identity?
When you work on a team, Git's identity stamps make it easy to see who changed what. Your name and email appear in the commit history, both locally and on GitHub.
The --global flag applies these settings to every Git project on your machine. You only need to do this once.
- Verify your identity is saved by running:
git config --global --list
You should see user.name and user.email in the output with the values you just set.
Don't see your name or email?
Make sure you included the quotes around your name and email in the commands. Without quotes, Git may only save the first word.
Help me fix my Git config
Verify your GitHub authentication
Later in this project, you will push code from your local machine to GitHub. For that to work, your terminal needs a way to prove your identity to GitHub.
The quickest way to check is with the GitHub CLI. If you do not have it installed, that is perfectly fine. You can authenticate with HTTPS when you push later.
- Check if the GitHub CLI is set up by running:
gh auth status
✔️ I see my GitHub username
The output shows your GitHub account and the authentication method (token or SSH). You are all set to push code to GitHub.
ⓧ Command not found or not logged in
No worries. The GitHub CLI is optional for this project. You have two other ways to authenticate when you push code to GitHub later.
- HTTPS with a personal access token: When you run git push for the first time, Git will ask for your GitHub username and a password. Use a personal access token (not your GitHub password) as the password. You can create one in GitHub under Settings > Developer settings > Personal access tokens.
- SSH key: If you already have an SSH key added to your GitHub account, you can use the SSH remote URL instead of HTTPS when linking your repository later.
Either method works. You will set up the connection in the next step when you push your first commit.
Your tools are verified and your Git identity is configured. Next up, you will create a local Git repository, write your first HTML, and push it all to GitHub.
Initialize a Local Repository and Push to GitHub
Your tools are verified and your Git identity is configured. Time to start the actual project.
Every codebase starts as a local folder that Git tracks for changes. In this step, you'll create a project folder, write a starter HTML page, and push it all to GitHub so it lives in the cloud too.
In this step, get ready to:
- Create a local Git repository with a starter HTML file.
- Create a new repository on GitHub.
- Connect the two and push your code.
Create a project folder and initialize Git
A Git repository is a folder that Git watches for changes. Initializing one tells Git to start tracking everything inside it.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and initialize it as a Git repository by running these commands:
mkdir portfolio-site
cd portfolio-site
git init
You should see a message saying Initialized empty Git repository.
Seeing a 'file exists' error?
A folder called portfolio-site already exists on your Desktop. Delete it first or choose a different name.
Help me fix this folder error
Now open the portfolio-site folder in VS Code so you can create files in it.
- Click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the portfolio-site folder, and click Open.
Seeing a trust prompt?
VS Code may ask if you trust the authors of this folder. Click Yes, I trust the authors to continue.
- Open a new terminal by clicking Terminal in the menu bar, then New Terminal.
This terminal opens inside your portfolio-site folder automatically.
- Create a new file by clicking the new file icon in the Explorer sidebar on the left.
- Name the file index.html and press Enter.
- Paste the following HTML into the file:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Set character encoding and responsive viewport -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Page title shown in the browser tab -->
<title>My Portfolio</title>
</head>
<body>
<!-- Main heading visible on the page -->
<h1>My Portfolio</h1>
</body>
</html>
What does this code do?
- <!DOCTYPE html> tells the browser this is an HTML5 page.
- The <head> section contains metadata like the character encoding and page title. None of this is visible on the page itself.
- The <body> contains the visible content. Right now it is just a single heading.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Confirm the file exists by running:
ls
You should see index.html in the output.
Don't see index.html?
Make sure you saved the file inside the portfolio-site folder, not somewhere else. Check the VS Code Explorer sidebar to confirm the file appears under portfolio-site.
Help me find my index.html file
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Portfolio</title>
</head>
<body>
<h1>My Portfolio</h1>
</body>
</html>
- Stage and commit your new file by running these commands:
git add index.html
git commit -m "Initial commit: add HTML skeleton"
What do these commands do?
- git add index.html stages the file. This tells Git you want to include it in your next commit.
- git commit -m "..." saves a snapshot of your staged changes with a descriptive message. Think of it as a save point you can always return to.
- Confirm your commit was created by running:
git log --oneline
You should see one commit with the message Initial commit: add HTML skeleton.
Seeing 'nothing to commit'?
This means index.html was not staged. Run git add index.html first, then try the commit again.
Why is Git saying nothing to commit?
Create a GitHub repository
Your code lives on your machine right now. A repository on GitHub gives it a home in the cloud where you can back it up, share it, and collaborate with others.
- Open your browser and go to github.com.
- Click the + icon in the top-right corner.
- Select New repository.
- Enter portfolio-site as the Repository name.
- Leave the repository set to Public.
- Do NOT check any of the initialization options. Leave Add a README file, Add .gitignore, and Choose a license all unchecked.
- Click Create repository.
Why skip the README and .gitignore?
Your local folder already has content and a commit. If GitHub creates its own files, the two repositories will have conflicting histories that are tricky to merge.
Starting with an empty GitHub repo makes the first push seamless.
GitHub now shows a setup page with instructions for connecting your local repo.
- Find the section titled ...or push an existing repository from the command line.
- Copy the repository URL shown on that page. It looks like https://github.com/your-username/portfolio-site.git.
Link your local repo to GitHub and push
You have two separate repositories right now. One is local on your machine, and one is an empty shell on GitHub. Linking them creates a connection so you can push code from your machine to the cloud.
- Back in your VS Code terminal, rename your branch to main by running this command:
git branch -M main
Why rename the branch?
Older versions of Git name the default branch master. Running this command renames it to main, which is the modern standard. If your branch is already called main, this command does nothing.
- Connect your local repo to GitHub by running this command:
git remote add origin [[YOUR_REPO_URL="https://github.com/your-username/portfolio-site.git"]]
- Push your code to GitHub by running this command:
git push -u origin main
What do these commands do?
- git remote add origin tells your local repo where the GitHub repo lives. origin is the standard name for your primary remote.
- git push -u origin main uploads your main branch to GitHub. The -u flag sets up tracking so future pushes only need git push.
- Refresh your GitHub repository page in the browser.
You should see index.html listed and the commit message Initial commit: add HTML skeleton.
GitHub page still shows setup instructions?
Double check you copied the correct repository URL. Run git remote -v to see what URL is linked to your local repo.
If the URL is wrong, remove it with git remote remove origin and re-add it with the correct URL.
If you see an authentication error, make sure your GitHub credentials (personal access token or SSH key) are configured correctly.
Help me fix my git push to GitHub
Your project is on GitHub with a clean first commit. In the next step, you'll create a feature branch and build out the actual portfolio page with real content and styling.
Create a Feature Branch and Build the Portfolio
Your repository is on GitHub with a clean initial commit. Now it's time to build the actual portfolio page.
Professional developers don't build directly on main. They create feature branches to develop new content in isolation, then merge it back when it's ready.
In this step, get ready to:
- Create a feature branch for your portfolio content.
- Build out the HTML and CSS for your portfolio page.
- Commit and push the feature branch to GitHub.
Create and switch to a feature branch
A feature branch is a separate copy of your code where you can make changes without affecting main. If something goes wrong, your stable branch stays untouched.
- Create and switch to a new feature branch by running this command:
git checkout -b feature/portfolio-content
What does this command do?
- git checkout -b creates a new branch and switches to it in one step.
- feature/portfolio-content is the branch name. The feature/ prefix is a naming convention that signals this branch adds new functionality.
- Confirm you're on the new branch by running:
git branch
You should see feature/portfolio-content highlighted with an asterisk (*), showing it's your active branch.
Still on main?
Make sure you included -b in the command. Without it, git checkout tries to switch to an existing branch instead of creating a new one.
Why isn't my Git branch switching?
Build out the portfolio page
Your portfolio needs two files: index.html for the page structure and style.css for the visual styling.
- Open index.html in VS Code by clicking on it in the Explorer sidebar.
- Select all the existing content with Cmd+A (macOS) or Ctrl+A (Windows) and replace it with the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Portfolio</title>
<!-- Link the stylesheet for visual styling -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Page header with title and welcome message -->
<header>
<h1>My Portfolio</h1>
<p>Welcome to my personal portfolio site.</p>
</header>
<main>
<!-- About section with a short bio -->
<section id="about">
<h2>About Me</h2>
<p>Hi, I am a developer learning Git, GitHub, and AWS. I built this site as part of a hands-on project to practice version control and cloud deployment.</p>
</section>
<!-- Projects section with placeholder cards -->
<section id="projects">
<h2>Projects</h2>
<div class="project-grid">
<div class="project-card">
<h3>Project One</h3>
<p>A brief description of your first project. Replace this with a real project once you have one to showcase.</p>
</div>
<div class="project-card">
<h3>Project Two</h3>
<p>A brief description of your second project. This is a placeholder you can update anytime.</p>
</div>
<div class="project-card">
<h3>Project Three</h3>
<p>A brief description of your third project. Keep adding cards as you complete more work.</p>
</div>
</div>
</section>
</main>
<!-- Footer with tools credit -->
<footer>
<p>Built with HTML, CSS, Git, and AWS S3.</p>
</footer>
</body>
</html>
What does this HTML do?
- The <header> holds the page title and a welcome message.
- The <section id="about"> contains a short bio paragraph.
- The <section id="projects"> uses a grid of .project-card divs for three placeholder project cards.
- The <link rel="stylesheet" href="style.css"> in the <head> connects the CSS file you'll create next.
- Save index.html.
You won't see the styled result yet because the CSS file doesn't exist. You'll verify the full page after adding styles.
Seeing an error in VS Code?
Check that the opening and closing tags all match up. A missing </div> or </section> will cause problems.
Also make sure you replaced ALL of the old content. If any of the original skeleton remains mixed in, the page structure will break.
Help me fix my HTML errors.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Portfolio</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>My Portfolio</h1>
<p>Welcome to my personal portfolio site.</p>
</header>
<main>
<section id="about">
<h2>About Me</h2>
<p>Hi, I am a developer learning Git, GitHub, and AWS. I built this site as part of a hands-on project to practice version control and cloud deployment.</p>
</section>
<section id="projects">
<h2>Projects</h2>
<div class="project-grid">
<div class="project-card">
<h3>Project One</h3>
<p>A brief description of your first project. Replace this with a real project once you have one to showcase.</p>
</div>
<div class="project-card">
<h3>Project Two</h3>
<p>A brief description of your second project. This is a placeholder you can update anytime.</p>
</div>
<div class="project-card">
<h3>Project Three</h3>
<p>A brief description of your third project. Keep adding cards as you complete more work.</p>
</div>
</div>
</section>
</main>
<footer>
<p>Built with HTML, CSS, Git, and AWS S3.</p>
</footer>
</body>
</html>
Now let's create the stylesheet to make this page look polished.
- Create a new file called style.css in the same portfolio-site folder by running:
touch style.css
- Confirm the file was created by running:
ls
You should see both index.html and style.css listed in the output.
- Open style.css in VS Code by clicking on it in the Explorer sidebar.
- Add the foundation styles for the page reset, body layout, and header by pasting this code:
/* Reset default browser margins and padding */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Center the page content with a max width */
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
/* Style the top header with a blue accent */
header {
text-align: center;
padding: 40px 0;
border-bottom: 2px solid #0066cc;
margin-bottom: 40px;
}
header h1 {
font-size: 2.5rem;
color: #0066cc;
margin-bottom: 10px;
}
header p {
font-size: 1.1rem;
color: #666;
}
What does this CSS do?
- The * selector resets all browser default margins and padding so your layout starts from a clean slate.
- margin: 0 auto on the body centers all content horizontally on the page.
- The header gets a blue bottom border (#0066cc) that acts as a visual separator between the title and the rest of the page.
- Save style.css.
- Open index.html in your browser by finding it in Finder (macOS) or File Explorer (Windows) inside the portfolio-site folder on your Desktop, then double-clicking it.
You should see a centered blue heading that reads "My Portfolio" with a blue underline. The rest of the page content is unstyled.
Page looks completely unstyled?
Make sure style.css is in the same folder as index.html. The <link> tag in the HTML head references style.css by filename, so both files must live side by side.
Also confirm the filename is exactly style.css with no typos or extra spaces.
Help me figure out why my CSS isn't loading.
- Add the content section, project card, and footer styles below the existing code in style.css:
/* Space out each content section */
section {
margin-bottom: 40px;
}
section h2 {
font-size: 1.8rem;
color: #333;
margin-bottom: 15px;
padding-bottom: 5px;
border-bottom: 1px solid #ddd;
}
#about p {
font-size: 1.05rem;
color: #555;
}
/* Responsive grid for project cards */
.project-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-top: 15px;
}
/* Individual project card styling */
.project-card {
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
}
.project-card h3 {
font-size: 1.2rem;
color: #0066cc;
margin-bottom: 10px;
}
.project-card p {
font-size: 0.95rem;
color: #666;
}
/* Footer with a subtle top border */
footer {
text-align: center;
padding: 30px 0;
margin-top: 40px;
border-top: 1px solid #ddd;
color: #999;
font-size: 0.9rem;
}
What does this CSS do?
- .project-grid uses CSS Grid with auto-fit to create a responsive layout. Cards automatically wrap to a new row on smaller screens.
- Each .project-card gets a light gray background, rounded corners, and padding to look like a contained card.
- The footer uses a subtle top border to separate it from the main content.
- Save style.css and refresh your browser.
You should see three project cards arranged in a grid layout with rounded borders and gray backgrounds. The footer appears at the bottom with a thin top border.
Cards not showing up in a grid?
Check that the class names in your HTML match the CSS selectors exactly. The HTML uses class="project-grid" and class="project-card". Class names are case-sensitive.
Also make sure you pasted the new styles below the existing code, not replacing it. Both CSS blocks should be in the same file.
Help me fix my project card styles.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
padding: 40px 0;
border-bottom: 2px solid #0066cc;
margin-bottom: 40px;
}
header h1 {
font-size: 2.5rem;
color: #0066cc;
margin-bottom: 10px;
}
header p {
font-size: 1.1rem;
color: #666;
}
section {
margin-bottom: 40px;
}
section h2 {
font-size: 1.8rem;
color: #333;
margin-bottom: 15px;
padding-bottom: 5px;
border-bottom: 1px solid #ddd;
}
#about p {
font-size: 1.05rem;
color: #555;
}
.project-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-top: 15px;
}
.project-card {
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
}
.project-card h3 {
font-size: 1.2rem;
color: #0066cc;
margin-bottom: 10px;
}
.project-card p {
font-size: 0.95rem;
color: #666;
}
footer {
text-align: center;
padding: 30px 0;
margin-top: 40px;
border-top: 1px solid #ddd;
color: #999;
font-size: 0.9rem;
}
Stage, commit, and push your changes
Your portfolio looks great locally. Now you need to save this progress in Git and push it to GitHub so it's backed up remotely.
- Stage all new and modified files, then commit them by running these commands:
git add .
git commit -m "Add portfolio content and styling"
What do these commands do?
- git add . stages every new and changed file in the current folder. The . means "everything here."
- git commit -m saves a snapshot of your staged files with a descriptive message. This message shows up in your Git history so you know what each commit changed.
- Push your feature branch to GitHub by running:
git push -u origin feature/portfolio-content
What does this command do?
- git push uploads your local commits to the remote GitHub repository.
- -u origin feature/portfolio-content sets up tracking so future pushes from this branch only need git push without the extra arguments.
- Go to your portfolio-site repository on GitHub in your browser.
- Click the branch dropdown (it says main by default).
You should see feature/portfolio-content listed as a branch. Clicking it shows your updated index.html and the new style.css file.
Push rejected or authentication failed?
If you see an authentication error, your GitHub credentials may have expired. Try running gh auth login if you have the GitHub CLI, or generate a new personal access token from GitHub's settings and use it as your password when prompted.
If the push is rejected because of remote changes, run git pull origin feature/portfolio-content first to sync up, then try pushing again.
Help me fix my Git push error.
Your portfolio is built and your feature branch is on GitHub. Next up, you'll open a pull request to merge this work into main the way real development teams do.
Open a Pull Request and Merge on GitHub
In the last step, you built your portfolio page on a feature branch and pushed it to GitHub. Your code is sitting on a separate branch, waiting to be merged into main.
On real development teams, code doesn't just get merged directly. It goes through a pull request, where teammates review changes before they become part of the main codebase. In this step, you'll create your first pull request and merge it on GitHub.
In this step, get ready to:
- Open a pull request on GitHub for your feature branch.
- Review the code diff and merge the pull request.
- Pull the merged changes back to your local machine.
Create a pull request on GitHub
Your feature branch is on GitHub, but it hasn't been merged into main yet. A pull request is how you propose those changes and request a review before merging.
- Open your portfolio-site repository on GitHub in your browser.
- Look for the yellow banner near the top of the page that says your recently pushed branch has changes.
- Click Compare & pull request.
What if I don't see the banner?
The banner only appears shortly after pushing. If it's gone, click the Pull requests tab at the top of your repository page, then click New pull request.
Select feature/portfolio-content as the compare branch, then click Create pull request.
- In the Title field, enter Add portfolio content and styling.
- In the description box, write a short summary of what you changed, like Added About Me section, Projects section with three cards, and CSS styling.
- Click Create pull request.
What is a pull request?
A pull request (PR) is a proposal to merge one branch into another. It shows exactly what changed and gives your team a place to discuss the code before approving it.
Even when you're working solo, pull requests create a clean record of what was added and why.
Review and merge the pull request
Before merging, developers review the proposed changes. GitHub makes this easy with a visual diff that highlights every line that was added or removed.
- Click the Files changed tab at the top of your pull request page.
You should see a diff view of all the code you added. Green lines are additions. This is the same view your teammates would use to review your work.
- Click the Conversation tab to go back to the main pull request page.
- Click Merge pull request.
- Click Confirm merge.
GitHub shows a purple Merged badge. Your feature branch code is now part of main on GitHub.
Pull the merged changes to your local machine
Your code is merged on GitHub, but your local machine is still on the feature/portfolio-content branch. You need to switch back to main and download the latest changes.
- Switch to your main branch by running this command:
git checkout main
- Pull the merged changes from GitHub by running:
git pull origin main
What does git pull do?
`git pull` downloads the latest commits from the remote repository and merges them into your current branch. After this command, your local main branch matches what's on GitHub.
- Verify your full commit history by running:
git log --oneline
You should see your full commit history, including the merge commit from the pull request. This proves your local main branch is up to date with GitHub.
Not seeing the merge commit?
Make sure you ran git checkout main before pulling. If you pull while still on the feature branch, the merge commit won't appear.
Run git branch to check which branch you're on. If it says feature/portfolio-content, run git checkout main first, then git pull origin main again.
Help me sync my local main branch with GitHub after merging a pull request.
Your Git workflow is complete. You've branched, committed, pushed, opened a pull request, and merged. Next up, you'll deploy your portfolio site live on AWS S3.
Deploy to AWS S3
Your portfolio is complete, your Git history is clean, and your code lives safely on GitHub. Now it is time to put your site on the internet.
You will use AWS S3, Amazon's cloud storage service, to host your HTML and CSS as a publicly accessible website. S3 needs a few configuration steps before it can serve web pages, so let's walk through each one.
In this step, get ready to:
- Create an S3 bucket configured for public website hosting.
- Upload your portfolio files to S3 using the AWS CLI.
- Visit your live portfolio site in the browser.
Create an S3 bucket for static hosting
An S3 bucket is like a folder in Amazon's cloud. You will create one specifically configured to serve a website.
- Open your browser and sign in to the AWS Management Console.
- In the search bar at the top, type S3 and select S3 from the results.
- Click Create bucket.
- In the Bucket name field, enter a globally unique name like my-portfolio-site-yourname.
- Choose an AWS Region close to you from the dropdown.
- Scroll down to Block Public Access settings for this bucket.
- Uncheck Block all public access.
- A warning box appears asking you to acknowledge. Check the acknowledgment checkbox to confirm.
- Leave all other settings as defaults and click Create bucket.
You should see a green success banner at the top of the page, and your new bucket appears in the bucket list.
Why uncheck Block Public Access?
By default, S3 buckets block all public access to keep your data private. That is great for most use cases.
However, a website needs to be readable by everyone on the internet. Unchecking this setting allows you to add a policy that makes your site files publicly accessible.
Why do I need a unique bucket name?
S3 bucket names are globally unique across all AWS accounts worldwide. If someone else already has a bucket named my-portfolio-site, you cannot use that name. Adding your name or a random number to the end keeps it unique.
Bucket creation failed?
If you see an error about the bucket name already existing, try a different name. Add extra numbers or characters to make it unique.
If you see a permissions error, make sure you are signed in with an IAM user that has S3 access.
Help me troubleshoot my S3 bucket creation error.
Enable static website hosting and add a bucket policy
Your bucket exists, but it does not know it should serve web pages yet. You need to enable static website hosting and add a policy that lets anyone read your files.
- Click on your bucket name to open it.
- Click the Properties tab.
- Scroll down to Static website hosting and click Edit.
- Select Enable.
- In the Index document field, enter index.html.
- Click Save changes.
What is the index document?
The index document tells S3 which file to serve when someone visits your website URL without specifying a filename. Setting it to index.html means visitors see your portfolio page by default.
Now you need to add a bucket policy that grants public read access to your files.
- Click the Permissions tab.
- Scroll down to Bucket policy and click Edit.
- Paste the following policy into the editor, replacing the bucket name with your own:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::[[S3_BUCKET_NAME=\"my-portfolio-site-yourname\"]]/*"
}
]
}
What does this policy do?
This is an IAM policy written in JSON that tells AWS who can access your bucket and how.
- "Principal": "*" means anyone on the internet.
- "Action": "s3:GetObject" means they can read (download) objects, but not modify or delete them.
- "Resource" points to your specific bucket. The /* at the end means all objects inside it.
- Click Save changes.
You should see the policy appear in the Bucket policy section. A banner may also appear confirming the bucket now allows public access.
Seeing an Access Denied or policy error?
Make sure you replaced the bucket name in the Resource line with your actual bucket name. The ARN must match exactly.
If you see a "public access" error, go back and confirm that Block all public access is unchecked in the Permissions tab.
Help me fix my S3 bucket policy error.
Upload your site using the AWS CLI
Your bucket is ready to serve a website. Now you need to get your files into it. The AWS CLI can sync your local project folder directly to S3 in one command.
- In your VS Code terminal, make sure you are inside the portfolio-site folder.
- Upload all your project files to S3 by running this command:
aws s3 sync . s3://[[S3_BUCKET_NAME="my-portfolio-site-yourname"]] --exclude ".git/*"
What does this command do?
- aws s3 sync compares your local folder with the S3 bucket and uploads anything that is new or changed.
- The . refers to your current directory (the portfolio-site folder).
- --exclude ".git/*" skips your Git metadata. Those files are for version control, not for your website.
You should see output listing each uploaded file, like upload: ./index.html and upload: ./style.css.
Seeing an upload error?
If you see NoSuchBucket, double check that the bucket name in your command matches the exact name you gave your S3 bucket.
If you see a credentials error, run aws sts get-caller-identity to confirm your AWS CLI is still configured correctly.
Help me troubleshoot my aws s3 sync error.
Your files are in S3. Now let's find your website URL and see it live.
- Go back to the S3 console in your browser and click into your bucket.
- Click the Properties tab.
- Scroll down to Static website hosting.
- Copy the Bucket website endpoint URL displayed there.
- Open a new browser tab and paste the URL.
You should see your portfolio page with the blue "My Portfolio" heading, your About Me section, and your three project cards. Your site is live on the internet.
What does the website endpoint URL look like?
S3 website endpoints follow this format: http://BUCKET-NAME.s3-website-REGION.amazonaws.com. This is the public address anyone can use to view your site.
Seeing a 403 Forbidden or blank page?
A 403 error usually means the bucket policy is missing or has the wrong bucket name in the Resource ARN. Go to Permissions and verify the policy matches your bucket name exactly.
If you see a 404 error, confirm that static website hosting is enabled and the index document is set to index.html in the Properties tab.
My S3 static website is returning an error instead of my portfolio page.
Why S3 instead of a more modern hosting service?
AWS offers more automated hosting options like Amplify, but S3 is the better learning choice here. S3 teaches fundamental cloud concepts like buckets, permissions, and policies without adding extra abstraction layers.
Amplify would also automate your Git workflow, which defeats the purpose of practicing each Git step manually.
Secret mission
Simulate and Resolve a Merge Conflict
A merge conflict happens when two branches change the same line of code differently. This is the Git scenario that intimidates beginners the most, but once you have done it once, it stops being scary.
Before you go
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses AWS S3, which is covered by the AWS Free Tier (5 GB storage and 20,000 GET requests per month for your first 12 months).
Cost warning
If your AWS account is older than 12 months, the Free Tier no longer applies and you will be charged for S3 storage and requests. A small portfolio site costs pennies per month, but if you are not planning to keep it, delete the bucket to avoid any charges.
Resources you used:
- S3 bucket with static website hosting enabled and a public bucket policy.
- GitHub repository (portfolio-site).
- Local project folder (portfolio-site on your Desktop).
Keep everything running
No action needed. Choose this if you want your portfolio to stay live on the internet.
- Your S3 bucket stays active and your site remains publicly accessible at its website endpoint URL.
- The Free Tier covers 5 GB of storage and 20,000 GET requests per month for your first 12 months.
- A small HTML and CSS portfolio site stays well within these limits.
Pause - I'll come back to this later
Remove public access so your site is no longer live, but keep the files in S3 for later.
- Go to the S3 console and click into your bucket.
- Open the Permissions tab and scroll to Block public access.
- Click Edit and check Block all public access.
- Type confirm and click Save changes.
- Your files stay in the bucket, but the website endpoint stops serving content. When you are ready to resume, uncheck Block all public access to make the site live again.
Delete - I don't want to use this again
Remove all project resources and start fresh. This removes all AWS costs.
- Go to the S3 console and click into your bucket.
- Select all objects inside the bucket and click Delete. Type permanently delete to confirm.
- Go back to the S3 bucket list, select your bucket, and click Delete. Type the bucket name to confirm.
- Optionally, delete the portfolio-site GitHub repository by going to the repo's Settings page, scrolling to the bottom, and clicking Delete this repository.
- Optionally, delete the local portfolio-site folder from your Desktop.
Mission accomplished
That's a Wrap!
Nice work! You just built and deployed a personal portfolio site to AWS S3 using a professional Git workflow.
You've learned how to:
- Initialized a local Git repository, connected it to a GitHub remote, and managed code with feature branches.
- Opened a pull request on GitHub, reviewed a code diff, and merged changes back into your main branch.
- Deployed a live website to S3 using the AWS CLI sync command.
- Secret Mission: Simulated and resolved a merge conflict to handle competing code changes with confidence.
Ready to quiz yourself?