Deploy an HTTPS Site on EC2
Deploy an Nginx site on Amazon EC2 with trusted HTTPS and a health endpoint.
Introduction
30 Second Summary
A website link only tells part of the story. Reviewers also need clear evidence behind what they see.
In this project, you will deploy an Internee.pk migration status page to Amazon EC2 at a browser-trusted HTTPS address. You will document the result through GitHub and LinkedIn without presenting the unavailable application source as migrated.
What You'll Build
Open the public IPv4 address in a browser to see the Internee.pk status page load over trusted HTTPS with no certificate warning.
By the end of this project, you'll have:
- A public migration status page where visitors can see that the Ubuntu Server host, Nginx web server, and HTTPS transport are online.
- A trusted HTTPS flow that redirects HTTP requests to the same public IPv4 endpoint. Successful renewals reload Nginx automatically to keep the short-lived Let's Encrypt certificate active.
- A reproducible evidence package on GitHub that shows the architecture, sanitized configuration, and successful renewal results. A LinkedIn post points reviewers to the live proof and repository.
- Secret Mission: add a lightweight /health endpoint that returns only ok for monitoring checks.
Are there any prerequisites?
The walkthrough covers every server-side setup step. You do not need a domain or the Internee.pk application source.
Before We Start
This is your moment to define an honest project scope before any hands-on work begins. You are committing to an infrastructure proof that does not claim the unavailable application source was migrated.
Set Up a Secure Ubuntu EC2 Host
Your infrastructure proof needs a public Linux host that reviewers can reach. Amazon EC2 supplies that host.
Public reachability creates a security requirement. SSH access must stay limited to your current public IP.
In this step, get ready to:
- Verify that your local Linux device has an OpenSSH client.
- Launch an Ubuntu EC2 instance with restricted administrative access.
- Connect to the instance and install the deployment tools.
Check your local SSH client
The OpenSSH client creates the encrypted terminal connection to your EC2 instance. Your local Linux device may already include it.
- Check for the local SSH client by running this command:
ssh -V
What does this command do?
The command asks your local SSH client to print its version. A version string confirms that the client is available.
✔️ I see a version number
Your local SSH client is ready. You can use it to connect to the EC2 instance after launch.
ⓧ Command not found
Ubuntu-based and Debian-based Linux devices can install the missing client through the local package manager.
- Prepare to enter your local password if the package manager requests it.
- Confirm the installation if the package manager requests approval.
- Install the OpenSSH client by running this command:
sudo apt install openssh-client
What does this command do?
The command installs the OpenSSH client package on your local Linux device. This package provides the SSH command used for the EC2 connection.
- Verify the new installation by running the version check again:
ssh -V
What should I see?
You should now see an OpenSSH version string. That output confirms that your local device can start an SSH connection.
Still missing the SSH client?
Confirm that your local Linux distribution uses the Ubuntu or Debian package manager. Other distributions need the OpenSSH client installation process from their own package documentation.
Check that your local account can run administrative commands. Package installation requires local administrative permission.
Ask for help with the local installation.
Launch the secured EC2 instance
An EC2 security group controls which network traffic can reach the instance. You will allow public web traffic while keeping administrative access tied to your current IP.
- Sign in to the AWS Management Console with your AWS Free Plan account.
- Use the console search bar to open Amazon EC2.
- Click Launch instance.
- Enter internee-https-proof under Name and tags.
- Select the Canonical Ubuntu Server 24.04 LTS image under Application and OS Images (Amazon Machine Image).
- Select the AMD64 architecture.
- Choose t3.micro under Instance type.
- Confirm that the selected image and instance type are marked Free Tier eligible.
Your EC2 key-pair file is a login credential. Store it somewhere private because AWS does not need this file uploaded again.
- Choose an existing key pair under Key pair (login).
- Create a key pair there if your account has no suitable pair.
- Store the downloaded private key file outside any public repository.
- Record the private key path as /path/to/your-key.pem.
- Enable an auto-assigned public IPv4 address under Network settings.
- Set the SSH rule to TCP port 22 from your current public IP.
- Set the HTTP rule to TCP port 80 from 0.0.0.0/0.
- Set the HTTPS rule to TCP port 443 from 0.0.0.0/0.
Keep This Address Stable
Launching the instance consumes AWS Free Plan credits. The Free Plan incurs no charges unless the account is upgraded or paid-only services are activated.
Outside plan coverage, a public IPv4 address has a list price of $0.005 per hour. Stopping the instance releases its auto-assigned address.
Provisioning can take a few minutes. The instance is still starting while its state remains pending.
- Create the instance by clicking Launch instance.
- Return to the EC2 instance list.
- Select internee-https-proof.
- Wait for the instance state to show Running.
- Record the listed public IPv4 address as your-public-ip.
- Keep the instance running until you capture the final deployment evidence.
Your secured Linux host is now live. Public web traffic can reach it while SSH remains restricted to your current IP.
Connect and install the server tools
Nginx serves the web page through package version 1.24.0-2ubuntu7.19. Git retrieves the repository through package version 2.43.0-1ubuntu7.4.
Certbot manages the certificate workflow through release 5.9.0. Snap supplies the current stable Certbot release.
- Replace /path/to/your-key.pem in the command below with /path/to/your-key.pem.
- Replace your-public-ip in the command below with your-public-ip.
- Connect as the Ubuntu user by running this command:
ssh -i /path/to/your-key.pem ubuntu@your-public-ip
What does this command do?
- The identity option tells SSH which EC2 private key file proves your access.
- The Ubuntu username selects the default administrator account on the Canonical image.
- The public IP identifies the EC2 host that receives the connection.
Your terminal prompt should change to the Ubuntu host. That change confirms that the restricted SSH rule and key pair work.
SSH connection failing?
- Confirm that the key path points to the private key selected for this instance.
- Confirm that the security-group SSH source matches your current public IP.
- Confirm that the connection uses the ubuntu username.
Help me diagnose the EC2 SSH connection.
The Ubuntu package manager may request confirmation before installing Nginx. Approving that prompt allows the installation to continue.
- Confirm the package installation if requested.
- Refresh the package index and install Nginx by running this command:
sudo apt update && sudo apt install nginx
What does this command do?
- The first half refreshes Ubuntu's package information.
- The second half installs Nginx.
- Ubuntu starts the Nginx service after installation.
Nginx installation stopped?
Check that the EC2 instance still has internet access. Package downloads need an outbound connection to the Ubuntu repositories.
Try the command again after any temporary repository download problem clears.
Help me troubleshoot the Nginx package installation.
- Install Git from the refreshed Ubuntu repositories by running this command:
sudo apt install git
What does this command do?
The command installs Git from the Ubuntu repositories. You will use it to retrieve the public project repository in the next step.
Git installation stopped?
Confirm that the earlier package-index refresh completed successfully. An incomplete refresh can prevent the package manager from locating Git.
Help me troubleshoot the Git package installation.
The first Certbot Snap download can take a few minutes. Quiet periods during the download do not mean the session has frozen.
- Install the stable Certbot Snap by running this command:
sudo snap install certbot --classic
What does this command do?
The command installs Certbot from the Snap Store. The classic option gives Certbot the system access required for certificate management.
Certbot installation stopped?
Confirm that the EC2 instance still has outbound internet access. Snap needs that connection to download Certbot.
Help me troubleshoot the Certbot Snap installation.
- Expose the Certbot command through the standard command path by running this command:
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
What does this command do?
The symbolic link makes the Snap-installed Certbot binary available at /usr/local/bin/certbot. Later certificate commands can call Certbot directly.
Before you check the host, do you expect every command to print version information?
- Verify all three server tools from the active SSH session by running these commands:
nginx -v
git --version
certbot --version
What should I see?
- The first line prints Nginx version information.
- The second line prints Git version information.
- The third line prints Certbot version information.
That's the host foundation ready. Your secured EC2 instance can now receive the deployment files.
✔️ All three commands print versions
Nginx, Git, and Certbot are available in the SSH session. Your server-side tool setup is complete.
ⓧ I see an older version
Refresh each affected installation from its current package source. This brings the host back to the versions available for Ubuntu and the stable Snap channel.
- Refresh the package index and update Nginx by running this command:
sudo apt update && sudo apt install nginx
What does this command do?
The command refreshes Ubuntu's package information. It installs the current Nginx package offered to this host.
- Update Git from the refreshed Ubuntu repositories by running this command:
sudo apt install git
What does this command do?
The command installs the current Git package offered by the Ubuntu repositories.
- Refresh Certbot from its tracked Snap channel by running this command:
sudo snap refresh certbot
What does this command do?
The command checks the tracked Certbot Snap channel. It installs a newer revision when one is available.
- Return to the version check above after the updates finish.
ⓧ One or more commands are missing
A missing command means that its installation did not finish or Certbot is not linked into the command path.
- Install Nginx again if its command is missing by running:
sudo apt update && sudo apt install nginx
What does this command do?
The command refreshes the package index. It installs the Nginx package and starts the service.
- Install Git again if its command is missing by running:
sudo apt install git
What does this command do?
The command installs the Git package from the Ubuntu repositories.
- Install Certbot again if its command is missing by running:
sudo snap install certbot --classic
What does this command do?
The command installs Certbot from the stable Snap channel with the required system access.
- Create the Certbot command link if the Snap installation succeeded but the command remains missing:
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
What does this command do?
The symbolic link exposes the Snap binary through the standard command path.
- Return to the version check above after reinstalling the missing tool.
Your EC2 host is reachable through restricted SSH. Next, you will publish the Internee.pk migration proof over HTTP.
Publish the HTTP Migration Proof
Your Ubuntu Server host on Amazon EC2 is ready to serve traffic. It now needs a public artifact that proves Nginx can deliver your work.
This step publishes a visible page over HTTP from source stored on GitHub. A separate HTTPS check tests whether the public web ports provide encrypted service by themselves.
In this step, get ready to:
- Create a public GitHub repository for the infrastructure proof.
- Deploy the migration page through Nginx.
- Compare the public endpoint over HTTP with its HTTPS behavior.
Create the public GitHub repository
A public repository gives reviewers a sanitized source copy of the page. It also gives your EC2 instance a repeatable place to download the deployment files.
- In GitHub's top navigation, click New repository.
- Enter internee-ec2-https as the repository name.
- Select Public as the repository visibility.
- Select Add README.
- Click Create repository.
Good progress. Your infrastructure proof now has a public source repository with an initial README.
Keep Private Material Out
A public repository exposes every committed file. Keep your EC2 private key outside this repository.
Keep certificate private keys and account credentials out as well. The repository should contain only sanitized project evidence.
The first repository file contains the page that visitors see. Its status cards make the deployment easy to scan.
- Use the full-file reference in the second tab as the exact source for index.html:
✔️ Awesome, I've got everything!
Your index.html should match the complete file in the comparison tab.
ⓧ 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">
<meta name="description" content="Internee.pk AWS EC2 migration infrastructure proof">
<title>Internee.pk Migration Infrastructure Proof</title>
<style>
:root {
color-scheme: dark;
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
background: #08111f;
color: #e7eefb;
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
display: grid;
place-items: center;
padding: 2rem;
background:
radial-gradient(circle at top left, rgba(45, 212, 191, 0.18), transparent 34rem),
#08111f;
}
main {
width: min(760px, 100%);
padding: clamp(1.5rem, 5vw, 3.5rem);
border: 1px solid #29405f;
border-radius: 24px;
background: rgba(11, 25, 44, 0.94);
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
}
.eyebrow {
margin: 0 0 0.8rem;
color: #5eead4;
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.14em;
text-transform: uppercase;
}
h1 {
margin: 0;
font-size: clamp(2rem, 7vw, 4.3rem);
line-height: 1;
}
.lead {
max-width: 62ch;
margin: 1.4rem 0 2rem;
color: #b7c7df;
font-size: 1.08rem;
line-height: 1.7;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 0.8rem;
margin: 0;
padding: 0;
list-style: none;
}
.status-grid li {
padding: 1rem;
border: 1px solid #29405f;
border-radius: 16px;
background: #0d1c31;
}
.status-grid span,
.status-grid strong {
display: block;
}
.status-grid span {
margin-bottom: 0.35rem;
color: #89a0bf;
font-size: 0.78rem;
text-transform: uppercase;
}
.status-grid strong {
color: #f8fafc;
}
section {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid #29405f;
}
h2 {
margin-top: 0;
font-size: 1.1rem;
}
section p {
margin-bottom: 0;
color: #b7c7df;
line-height: 1.65;
}
.notice {
color: #fcd34d;
}
</style>
</head>
<body>
<main>
<p class="eyebrow">Internee.pk infrastructure proof</p>
<h1>Migration environment is online.</h1>
<p class="lead">
This verification page is running on Ubuntu Server in Amazon EC2,
served by Nginx, and protected by a browser-trusted Let's Encrypt
certificate issued directly for the public IPv4 address.
</p>
<ul class="status-grid" aria-label="Deployment status">
<li><span>Compute</span><strong>Amazon EC2</strong></li>
<li><span>Operating system</span><strong>Ubuntu Server</strong></li>
<li><span>Web server</span><strong>Nginx</strong></li>
<li><span>Transport</span><strong>HTTPS enabled</strong></li>
</ul>
<section>
<h2>Scope of this proof</h2>
<p>
The cloud host, networking, web server, TLS termination, renewal path,
and evidence workflow are complete. <span class="notice">The actual
Internee.pk application source is not included in this deployment.</span>
</p>
</section>
</main>
</body>
</html>
What Does This File Show?
- The eyebrow class labels the page as an infrastructure proof.
- The lead class summarizes the intended deployment.
- The status-grid class presents four deployment signals.
- The notice class highlights the application-source limitation.
- Click Add file in the repository toolbar.
- Click Create new file.
- Enter index.html in the file-name box.
- Paste the exact index.html content from the comparison tab.
- Enter Add migration proof page as the commit message.
- Click Commit changes.
GitHub returns you to the repository file list. You should see index.html beside README.md.
The second file defines the deliberate HTTP-only starting point. Its server block maps public requests to the page directory.
- Use the full-file reference in the second tab as the exact source for internee-http.conf:
✔️ Awesome, I've got everything!
Your internee-http.conf should match the complete file in the comparison tab.
ⓧ I'd like to double check the full code
server {
listen 80 default_server;
server_name _;
root /var/www/internee;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
What Does This Configuration Do?
- The server listens for HTTP traffic on port 80.
- The root directive points requests at /var/www/internee.
- The index directive selects index.html for directory requests.
- The try_files directive returns a missing-page response when no requested file exists.
- Click Add file in the repository toolbar.
- Click Create new file.
- Enter internee-http.conf in the file-name box.
- Paste the exact internee-http.conf content from the comparison tab.
- Enter Add HTTP Nginx server block as the commit message.
- Click Commit changes.
The public repository should now list README.md. It should also list index.html and internee-http.conf.
Deploy the repository files
The repository is your source copy. The Ubuntu server needs its own clone before Nginx can serve the page.
- Replace your-github-username in the command below with your GitHub username.
- Clone the public repository to your Ubuntu home directory by running this command:
git clone https://github.com/your-github-username/internee-ec2-https.git
What Does This Command Do?
The command downloads the public repository into a new internee-ec2-https directory. A public HTTPS clone does not require GitHub credentials on the EC2 instance.
- Deploy the page and server block to their Nginx locations by running these commands:
cd internee-ec2-https
sudo mkdir -p /var/www/internee
sudo cp index.html /var/www/internee/index.html
sudo cp internee-http.conf /etc/nginx/sites-available/internee
How Are the Files Placed?
- The first command moves your terminal into the cloned repository.
- The second command creates the /var/www/internee web directory.
- The third command copies the page into that web directory.
- The final command installs the server block in /etc/nginx/sites-available.
- Confirm both deployed files exist by running this command:
ls -l /var/www/internee/index.html /etc/nginx/sites-available/internee
What Should I See?
You should see one listing for /var/www/internee/index.html. You should also see one for /etc/nginx/sites-available/internee.
Missing a Deployed File?
- Check that GitHub lists both source files with the exact capitalization shown above.
- Confirm your terminal is connected to internee-https-proof as ubuntu.
- Check that the cloned directory is named internee-ec2-https.
Help me diagnose missing deployment files on my Ubuntu EC2 instance.
Enable the site and test both protocols
A server block affects traffic after it is enabled. Nginx also needs its default site removed so the new configuration owns port 80.
- Enable the internee site and remove the enabled default site by running these commands:
sudo ln -s /etc/nginx/sites-available/internee /etc/nginx/sites-enabled/internee
sudo rm /etc/nginx/sites-enabled/default
What Changed?
The symbolic link adds the internee server block to the enabled configuration set. Removing the default link prevents the packaged site from answering the same HTTP traffic.
- Test the enabled Nginx configuration by running this command:
sudo nginx -t
Why Test Before Reloading?
The syntax test checks the enabled configuration before Nginx applies it. You should see confirmation that the configuration is valid.
Seeing a Configuration Error?
- Compare /etc/nginx/sites-available/internee with the complete internee-http.conf reference.
- Check that every opening brace has a matching closing brace.
- Confirm the enabled link points to /etc/nginx/sites-available/internee.
Help me troubleshoot my Nginx syntax test.
- Apply the valid configuration by running this command:
sudo systemctl reload nginx
What Does the Reload Do?
The reload makes Nginx adopt the enabled server block without stopping the web service. New HTTP requests now use the Internee.pk document root.
Before you test the endpoint, what do you expect Nginx to return over HTTP?
- Enter http://your-public-ip in your browser address bar using the instance's public IPv4 address.
You should see the dark Internee.pk migration page with four status cards. The page should also show the source-scope notice.
That is your first public deployment win. Nginx is now serving your infrastructure proof from the EC2 instance.
Before you test the second protocol, do you expect the same page to load over HTTPS?
- Enter https://your-public-ip in your browser address bar using the same public IPv4 address.
The HTTPS connection should fail before the page loads. This is the intended shortfall in the current deployment.
What Did the Failure Prove?
Opening port 443 permits public traffic to reach the instance. The current Nginx configuration has no TLS listener or certificate for that traffic.
Your working HTTP page proves that networking and static serving are ready. The failed HTTPS check isolates the missing certificate workflow.
Your migration proof is public over HTTP. Next, you will issue a trusted certificate for the EC2 public IPv4 address.
Obtain a Let's Encrypt IP Certificate
Your Nginx page is live over HTTP. The failed HTTPS check proved the server still lacks a TLS identity.
To secure the raw public IP, you will ask Let's Encrypt for a browser-trusted certificate through Certbot. The short-lived profile requires frequent automated validation through HTTP-01.
In this step, get ready to:
- Confirm that staging validation can reach the current webroot.
- Replace the staging lineage with a trusted certificate.
- Verify the trusted certificate name and file paths.
Test HTTP-01 validation against staging
The PUBLIC_IP shell variable keeps the address consistent across the staging request and the trusted request.
- Set PUBLIC_IP to your EC2 public IPv4 address by running this command:
PUBLIC_IP=[[PUBLIC_IP="your-public-ip"]]
What does this command do?
The shell stores your EC2 public IPv4 address under PUBLIC_IP. Both certificate requests can now reuse the same address.
- Replace your-email@example.com with your contact email in the command below.
- Test the certificate request against the staging environment by running:
sudo certbot certonly --staging --preferred-profile shortlived --webroot --webroot-path /var/www/internee --ip-address "$PUBLIC_IP" --cert-name internee-ip-staging --email [[EMAIL="your-email@example.com"]] --agree-tos --no-eff-email
What does this command do?
- The --staging flag sends this test request to the Let's Encrypt staging environment.
- The --preferred-profile flag selects the shortlived certificate profile required for IP certificates.
- The --webroot-path flag points Certbot to /var/www/internee for the temporary validation file.
- The --ip-address flag requests coverage for the public IPv4 address stored in PUBLIC_IP.
- Review the terminal output after Certbot completes the staging request.
You should see confirmation that Certbot completed validation for the public IPv4 address. Your HTTP migration proof continues to respond through the same webroot.
Staging validation did not complete?
- Confirm that PUBLIC_IP contains the current EC2 public IPv4 address.
- Confirm that the EC2 security group still permits public traffic on port 80.
- Open the existing HTTP page to confirm that Nginx can still serve files from /var/www/internee.
Help me diagnose why Certbot staging HTTP-01 validation cannot reach my EC2 webroot.
Replace the staging lineage
The staging request proves that Let's Encrypt can reach the challenge file through port 80. That temporary lineage has now served its purpose.
- Delete only the temporary staging lineage by running:
- Confirm the deletion if Certbot prompts you.
sudo certbot delete --cert-name internee-ip-staging
What does this command do?
The --cert-name flag targets only internee-ip-staging. Certbot removes that managed test lineage from its certificate store.
Could Certbot not find the staging lineage?
Return to the staging request output. Confirm that the request completed before you try the deletion again.
Help me check why the staging lineage is missing from Certbot.
Production issuance creates the browser-trusted lineage that Nginx uses in the next step.
- Request the trusted IP certificate by running:
sudo certbot certonly --preferred-profile shortlived --webroot --webroot-path /var/www/internee --ip-address "$PUBLIC_IP" --cert-name internee-ip --email [[EMAIL="your-email@example.com"]] --agree-tos --no-eff-email
What changes in this request?
Removing --staging sends the request to the production certificate service. The lineage name internee-ip gives Nginx a stable certificate path to reference.
The webroot workflow leaves the active HTTP site in place during validation. Certbot stores the issued certificate under its managed directory.
That's the certificate secured. Let's Encrypt now recognizes your public IPv4 address.
Trusted issuance did not complete?
- Confirm that the staging request completed successfully before retrying production issuance.
- Set PUBLIC_IP again if you reconnected to the instance after the staging test.
- Confirm that the HTTP migration proof still opens at the current public IPv4 address.
Help me troubleshoot the trusted Certbot IP certificate request.
Confirm the certificate lineage
Certbot's certificate inventory confirms the lineage name and the files available for Nginx.
Before you run the check, predict which lineage Certbot lists now.
- Display the managed certificate inventory by running:
sudo certbot certificates
What should you see?
- Look for Certificate Name: internee-ip in the output.
- Look for your EC2 public IPv4 address among the covered identifiers.
- Look for /etc/letsencrypt/live/internee-ip/fullchain.pem as the certificate path.
- Look for /etc/letsencrypt/live/internee-ip/privkey.pem as the private-key path.
Your trusted IP certificate is ready for Nginx. The existing index.html file and internee-http.conf configuration remain unchanged.
Do you only see the staging lineage?
Confirm that the production request used internee-ip as its certificate name. Run the trusted request again if that lineage is absent.
Help me find why Certbot does not list the internee-ip lineage.
The certificate now exists on the instance. Next up, you will connect those managed files to Nginx and redirect every HTTP request to trusted HTTPS.
Enable HTTPS and Automate Renewal
The browser-trusted certificate is ready. However, Certbot has only obtained it. Nginx still has no TLS listener connected to the certificate files.
You will connect the certificate to Nginx so the public IP serves trusted HTTPS. You will also install a deploy hook that reloads Nginx after every successful renewal.
In this step, get ready to:
- Connect Nginx to the trusted IP certificate.
- Confirm that HTTP redirects to the trusted HTTPS page.
- Install a deploy hook that validates Nginx after each successful renewal.
Connect Nginx to the IP certificate
The cloned GitHub repository already contains internee-https.conf. This configuration preserves certificate validation over port 80. It also adds the encrypted server on port 443.
- Replace the deployed HTTP-only configuration by running this command:
sudo cp ~/internee-ec2-https/internee-https.conf /etc/nginx/sites-available/internee
Why configure Nginx manually?
Certbot can obtain an IP certificate. Its Nginx installer does not support installing IP certificates, so the server block points directly to the certificate lineage.
- The port 80 server keeps /.well-known/acme-challenge/ reachable for future validation.
- The remaining HTTP requests receive a permanent redirect to the same address over HTTPS.
- The port 443 server reads /etc/letsencrypt/live/internee-ip/fullchain.pem as the certificate chain.
- The port 443 server reads /etc/letsencrypt/live/internee-ip/privkey.pem as the private key.
- Predict whether Nginx can read the new server blocks and both certificate files.
- Test the replacement configuration by running:
sudo nginx -t
What does this check do?
The syntax test parses every enabled Nginx configuration. It also checks whether referenced files can be opened before the live service changes.
The test should confirm that the Nginx configuration is valid. This proves the TLS server can access the certificate lineage.
- Apply the validated configuration by running:
sudo systemctl reload nginx
What does the reload do?
The reload activates the new server blocks without stopping the Nginx service. New requests can now reach the TLS listener on port 443.
Configuration test not passing?
- Confirm that the source file is named internee-https.conf inside ~/internee-ec2-https.
- Check that both certificate paths contain the lineage name internee-ip.
- Confirm that every Nginx directive ends with the punctuation shown in the repository file.
Help me diagnose why my HTTPS Nginx configuration does not pass its syntax test.
Verify the trusted HTTPS redirect
The reload gives the public endpoint a new path from unencrypted traffic to the encrypted server. The browser check proves that the redirect and certificate work together.
- Predict whether the HTTP request will remain unencrypted or move to the secure URL.
- Enter http:// followed by your-public-ip in your browser address bar.
- Press Enter.
Your browser should move to the matching https:// address. You should see the Internee.pk migration page without a certificate warning.
- Inspect the connection certificate through your browser's site controls.
- Confirm that the certificate covers your-public-ip.
That is the key security milestone complete. Your public IPv4 endpoint now presents a browser-trusted certificate before serving the migration proof.
Still seeing a connection warning?
- Confirm that the browser moved to the same public IPv4 address over https://.
- Confirm that inbound port 443 remains open in the EC2 security group from earlier.
- Rerun the Nginx syntax test before reloading the service again.
Help me troubleshoot why my EC2 public IP still shows an HTTPS warning after I configured Nginx with the internee-ip certificate.
Install and test the renewal hook
IP certificates use the short-lived profile, so renewal happens frequently. A deploy hook ensures that Nginx starts using each renewed certificate after Certbot finishes successfully.
- Copy reload-nginx.sh into the Certbot deploy-hook directory by running:
sudo cp ~/internee-ec2-https/reload-nginx.sh /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Where does the hook run?
Certbot runs executable files in /etc/letsencrypt/renewal-hooks/deploy after a successful renewal. The script tests the configuration before asking Nginx to reload.
- Make the deployed hook executable by running:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Why add execute permission?
The execute permission allows Certbot to run the deploy hook as a script. The hook stays dormant until a renewal succeeds or a dry run explicitly exercises it.
- Predict whether the deploy hook can validate and reload Nginx during a simulated renewal.
- Exercise the renewal workflow by running:
sudo certbot renew --dry-run --run-deploy-hooks
What does the dry run prove?
- The renewal dry run tests future validation against the Let's Encrypt staging service.
- The --run-deploy-hooks flag runs the deploy hook during the simulation.
- The hook runs nginx -t before it runs nginx -s reload.
The renewal simulation should complete successfully. This confirms that future certificates can be validated before Nginx reloads them.
- Refresh the trusted HTTPS migration page in your browser.
You should still see the Internee.pk migration page without a certificate warning. The live endpoint remains trusted after the renewal workflow runs.
Renewal simulation not succeeding?
- Confirm that /.well-known/acme-challenge/ remains available through the port 80 server block.
- Confirm that reload-nginx.sh exists inside /etc/letsencrypt/renewal-hooks/deploy.
- Confirm that the deployed hook has execute permission.
Help me troubleshoot a failed Certbot renewal dry run or deploy hook on my Ubuntu EC2 instance.
✔️ Awesome, I've got everything!
Your HTTPS configuration and renewal hook are deployed. Both files match the working project versions.
ⓧ 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">
<meta name="description" content="Internee.pk AWS EC2 migration infrastructure proof">
<title>Internee.pk Migration Infrastructure Proof</title>
<style>
:root {
color-scheme: dark;
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
background: #08111f;
color: #e7eefb;
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
display: grid;
place-items: center;
padding: 2rem;
background:
radial-gradient(circle at top left, rgba(45, 212, 191, 0.18), transparent 34rem),
#08111f;
}
main {
width: min(760px, 100%);
padding: clamp(1.5rem, 5vw, 3.5rem);
border: 1px solid #29405f;
border-radius: 24px;
background: rgba(11, 25, 44, 0.94);
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
}
.eyebrow {
margin: 0 0 0.8rem;
color: #5eead4;
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.14em;
text-transform: uppercase;
}
h1 {
margin: 0;
font-size: clamp(2rem, 7vw, 4.3rem);
line-height: 1;
}
.lead {
max-width: 62ch;
margin: 1.4rem 0 2rem;
color: #b7c7df;
font-size: 1.08rem;
line-height: 1.7;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 0.8rem;
margin: 0;
padding: 0;
list-style: none;
}
.status-grid li {
padding: 1rem;
border: 1px solid #29405f;
border-radius: 16px;
background: #0d1c31;
}
.status-grid span,
.status-grid strong {
display: block;
}
.status-grid span {
margin-bottom: 0.35rem;
color: #89a0bf;
font-size: 0.78rem;
text-transform: uppercase;
}
.status-grid strong {
color: #f8fafc;
}
section {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid #29405f;
}
h2 {
margin-top: 0;
font-size: 1.1rem;
}
section p {
margin-bottom: 0;
color: #b7c7df;
line-height: 1.65;
}
.notice {
color: #fcd34d;
}
</style>
</head>
<body>
<main>
<p class="eyebrow">Internee.pk infrastructure proof</p>
<h1>Migration environment is online.</h1>
<p class="lead">
This verification page is running on Ubuntu Server in Amazon EC2,
served by Nginx, and protected by a browser-trusted Let's Encrypt
certificate issued directly for the public IPv4 address.
</p>
<ul class="status-grid" aria-label="Deployment status">
<li><span>Compute</span><strong>Amazon EC2</strong></li>
<li><span>Operating system</span><strong>Ubuntu Server</strong></li>
<li><span>Web server</span><strong>Nginx</strong></li>
<li><span>Transport</span><strong>HTTPS enabled</strong></li>
</ul>
<section>
<h2>Scope of this proof</h2>
<p>
The cloud host, networking, web server, TLS termination, renewal path,
and evidence workflow are complete. <span class="notice">The actual
Internee.pk application source is not included in this deployment.</span>
</p>
</section>
</main>
</body>
</html>
What does this file provide?
The unchanged index.html file provides the public migration proof served by both Nginx configurations.
server {
listen 80 default_server;
server_name _;
root /var/www/internee;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
What does the starting configuration show?
The internee-http.conf file preserves the deliberate HTTP-only starting point in the evidence repository.
server {
listen 80 default_server;
server_name _;
root /var/www/internee;
location ^~ /.well-known/acme-challenge/ {
try_files $uri =404;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl default_server;
server_name _;
root /var/www/internee;
index index.html;
ssl_certificate /etc/letsencrypt/live/internee-ip/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/internee-ip/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
try_files $uri $uri/ =404;
}
}
What does the HTTPS configuration provide?
The internee-https.conf file preserves HTTP-01 validation. It redirects normal HTTP traffic and serves the migration page with the trusted IP certificate.
#!/bin/sh
set -eu
nginx -t
nginx -s reload
What does the deploy hook provide?
The reload-nginx.sh hook stops if validation fails. A successful test triggers a graceful Nginx reload.
Your migration proof now has trusted HTTPS and an automated certificate reload path. Next up, you will publish sanitized evidence so reviewers can verify the deployment safely.
Publish the Deployment Evidence
Your trusted HTTPS page is live. However, a live server gives an evaluator only one snapshot of the deployment.
This final step turns your AWS deployment into sanitized GitHub evidence. You will also publish a LinkedIn summary that points reviewers to the working endpoint and repository.
In this step, get ready to:
- Document the live deployment with a detailed README and redacted screenshots.
- Create a reusable LinkedIn post draft in the public repository.
- Publish the project post and verify that the evidence is publicly visible.
Document the deployment on GitHub
Deployment evidence connects the public result to the decisions behind it. Your README will document the architecture, validation results, source limitation, security guidance, and lifecycle plan.
- Return to the EC2 console from earlier.
- Record the instance's AWS Region here: your-aws-region.
- Record the trusted public endpoint here: https://your-public-ip/.
- Return to your public internee-ec2-https repository.
- Record the repository URL here: https://github.com/your-github-username/internee-ec2-https.
- Select README.md in the repository file list.
- Select the pencil-shaped edit control above the file.
- Replace the editor contents with this first documentation section:
# Internee.pk EC2 HTTPS Infrastructure Proof
This repository documents a domainless AWS EC2 deployment using Ubuntu Server, Nginx, and a short-lived Let's Encrypt certificate issued for a public IPv4 address.
## Live endpoint
- HTTPS: `https://your-public-ip/`
- AWS Region: `your-aws-region`
## Scope
This is an infrastructure proof. It demonstrates the compute host, network access, Nginx web serving, TLS termination, HTTP redirection, and certificate renewal path. The actual Internee.pk application source was not available and is not represented as migrated.
## Architecture
```text
Public visitor
|
| TCP 80 and 443
v
EC2 security group
|
v
Nginx on Ubuntu Server 24.04 LTS
| \
| static page \ HTTP-01 challenge files
v v
/var/www/internee/ Let's Encrypt validation
|
v
Trusted HTTPS response
```
What does this section document?
- The live endpoint and Region identify where the deployment runs.
- The scope statement makes the unavailable application source explicit.
- The architecture traces public traffic through the Amazon EC2 security group to Nginx and the certificate validation path.
- Replace https://your-public-ip/ with https://your-public-ip/.
- Replace your-aws-region with your-aws-region.
- Select Commit changes above the editor.
- Enter Document live endpoint and architecture as the commit message.
- Select Commit changes in the commit dialog.
You should see the live endpoint, source limitation, and architecture diagram rendered in README.md.
Does the architecture render incorrectly?
- Confirm that the architecture starts with ```text and ends with ```.
- Check that the live endpoint begins with https://.
Ask for help checking the Markdown structure in your README.
- Select the pencil-shaped edit control above README.md again.
- Place the cursor after the architecture code fence.
- Add the tool details and validation checklist below:
## Verified tool versions
- Nginx package: `1.24.0-2ubuntu7.19`
- Certbot release: `5.9.0`
- Git package: `1:2.43.0-1ubuntu7.4`
## Repository files
- `index.html`: public migration verification page
- `internee-http.conf`: deliberate HTTP-only starting point
- `internee-https.conf`: HTTPS server and HTTP redirect
- `reload-nginx.sh`: deploy hook that validates and reloads Nginx
- `linkedin-post.txt`: editable project-post draft
## Validation evidence
- [ ] EC2 instance state is running
- [ ] SSH is limited to my current public IP
- [ ] HTTP first served the verification page
- [ ] HTTPS initially failed before TLS was configured
- [ ] `sudo nginx -t` reported successful syntax
- [ ] `sudo certbot certificates` listed `internee-ip`
- [ ] HTTP redirects to the HTTPS IP URL
- [ ] HTTPS opens without a certificate warning
- [ ] `sudo certbot renew --dry-run --run-deploy-hooks` succeeded
What does this section prove?
- The version list records the server-side tools used for the deployment.
- The repository list explains the purpose of each sanitized project file.
- The checklist connects each deployment claim to a result you verified.
- Select each checklist item that your completed deployment proves.
- Select Commit changes above the editor.
- Enter Add versions and validation evidence as the commit message.
- Select Commit changes in the commit dialog.
You should see the tool versions, repository file guide, and completed validation checklist below the architecture.
Did the new sections join the diagram?
Confirm that you added the new headings after the architecture's closing code fence. Content placed inside that fence renders as part of the diagram.
Help me find why my GitHub README headings appear inside the architecture diagram.
- Select the pencil-shaped edit control above README.md again.
- Place the cursor after the final validation checklist item.
- Add the security and lifecycle guidance below:
## Security notes
- Never commit the EC2 private key.
- Never commit `/etc/letsencrypt/live/internee-ip/privkey.pem`.
- Redact account IDs and unrelated personal data from screenshots.
- Keep SSH restricted to the administrator's current public IP.
## Cost and lifecycle
The AWS Free Plan prevents out-of-pocket charges while the account remains on that plan, but the deployment consumes credits. Stopping an instance releases its auto-assigned public IPv4 address. If the address changes, issue a new IP certificate and update the shared URLs.
Why include lifecycle guidance?
The security notes show how the public evidence avoids private keys and account credentials. The lifecycle section explains why stopping the instance breaks the current IP-based certificate and shared URL.
- Select Commit changes above the editor.
- Enter Document security and lifecycle as the commit message.
- Select Commit changes in the commit dialog.
Your rendered README should now end with security guidance and the public IPv4 lifecycle plan.
Are the final sections missing?
Return to the repository history and confirm that the latest README commit is present. Reopen the editor if the security notes were left in an uncommitted draft.
Help me check why my latest GitHub README changes are not visible.
✔️ Awesome, I've got everything!
Your README now documents the deployment from public endpoint through renewal and lifecycle planning.
ⓧ I'd like to double check the full code
# Internee.pk EC2 HTTPS Infrastructure Proof
This repository documents a domainless AWS EC2 deployment using Ubuntu Server, Nginx, and a short-lived Let's Encrypt certificate issued for a public IPv4 address.
## Live endpoint
- HTTPS: `https://your-public-ip/`
- AWS Region: `your-aws-region`
## Scope
This is an infrastructure proof. It demonstrates the compute host, network access, Nginx web serving, TLS termination, HTTP redirection, and certificate renewal path. The actual Internee.pk application source was not available and is not represented as migrated.
## Architecture
```text
Public visitor
|
| TCP 80 and 443
v
EC2 security group
|
v
Nginx on Ubuntu Server 24.04 LTS
| \
| static page \ HTTP-01 challenge files
v v
/var/www/internee/ Let's Encrypt validation
|
v
Trusted HTTPS response
```
## Verified tool versions
- Nginx package: `1.24.0-2ubuntu7.19`
- Certbot release: `5.9.0`
- Git package: `1:2.43.0-1ubuntu7.4`
## Repository files
- `index.html`: public migration verification page
- `internee-http.conf`: deliberate HTTP-only starting point
- `internee-https.conf`: HTTPS server and HTTP redirect
- `reload-nginx.sh`: deploy hook that validates and reloads Nginx
- `linkedin-post.txt`: editable project-post draft
## Validation evidence
- [ ] EC2 instance state is running
- [ ] SSH is limited to my current public IP
- [ ] HTTP first served the verification page
- [ ] HTTPS initially failed before TLS was configured
- [ ] `sudo nginx -t` reported successful syntax
- [ ] `sudo certbot certificates` listed `internee-ip`
- [ ] HTTP redirects to the HTTPS IP URL
- [ ] HTTPS opens without a certificate warning
- [ ] `sudo certbot renew --dry-run --run-deploy-hooks` succeeded
## Security notes
- Never commit the EC2 private key.
- Never commit `/etc/letsencrypt/live/internee-ip/privkey.pem`.
- Redact account IDs and unrelated personal data from screenshots.
- Keep SSH restricted to the administrator's current public IP.
## Cost and lifecycle
The AWS Free Plan prevents out-of-pocket charges while the account remains on that plan, but the deployment consumes credits. Stopping an instance releases its auto-assigned public IPv4 address. If the address changes, issue a new IP certificate and update the shared URLs.
Keep public evidence safe
These screenshots become public evidence. Safe evidence shows the success state while keeping private keys, credentials, account IDs, and unrelated personal data out of view.
- Return to the EC2 console and capture the running instance state.
- Capture the browser after the HTTP address redirects to the HTTPS address.
- Capture the trusted HTTPS migration page.
- Capture the successful renewal dry-run output from the EC2 terminal session.
- Redact sensitive account data from each screenshot.
What should each screenshot prove?
Each image should support one validation claim without exposing unrelated console details. A reviewer should be able to connect the image to the corresponding README checklist item.
- Select Add file in the repository.
- Select Upload files.
- Upload the four redacted screenshots.
- Enter a commit message describing the deployment evidence.
- Select Commit changes.
You should see the redacted evidence images in the public repository without any private key or credential visible.
- Select Add file in the repository.
- Select Create new file.
- Enter linkedin-post.txt as the filename.
- Add the reusable project-post draft below:
I deployed an HTTPS-secured Internee.pk infrastructure proof on AWS EC2.
What I implemented:
- Canonical Ubuntu Server on a Free Tier-eligible EC2 instance
- SSH restricted to my current public IP
- Nginx static hosting and HTTP-to-HTTPS redirection
- A browser-trusted Let's Encrypt certificate for the EC2 public IPv4 address
- Automated certificate renewal with an Nginx reload hook
- A public GitHub repository with sanitized configuration and validation evidence
Live HTTPS endpoint:
https://your-public-ip/
GitHub repository:
https://github.com/your-github-username/internee-ec2-https
Scope note: this is the verified cloud infrastructure and HTTPS deployment path. The actual Internee.pk application source was not available, so I am not presenting the application itself as migrated.
#AWS #EC2 #Linux #Nginx #HTTPS #LetsEncrypt #CloudComputing
How is the post structured?
- The opening names the infrastructure proof without claiming that the unavailable application was migrated.
- The implementation list summarizes the security, web serving, certificate, renewal, and evidence work.
- The final sections provide spaces for the live endpoint and repository URL.
- Select Commit changes above the editor.
- Enter Add LinkedIn post draft as the commit message.
- Select Commit changes in the commit dialog.
You should see linkedin-post.txt beside the existing HTML, Nginx configuration, renewal hook, and README files.
Is the draft missing from the repository?
Confirm that the filename is exactly linkedin-post.txt. Check the repository history for the commit if GitHub returned you to the file editor.
Help me troubleshoot why linkedin-post.txt is missing after I committed it on GitHub.
✔️ Awesome, I've got everything!
Your repository now contains the reusable public-post draft.
ⓧ I'd like to double check the full code
I deployed an HTTPS-secured Internee.pk infrastructure proof on AWS EC2.
What I implemented:
- Canonical Ubuntu Server on a Free Tier-eligible EC2 instance
- SSH restricted to my current public IP
- Nginx static hosting and HTTP-to-HTTPS redirection
- A browser-trusted Let's Encrypt certificate for the EC2 public IPv4 address
- Automated certificate renewal with an Nginx reload hook
- A public GitHub repository with sanitized configuration and validation evidence
Live HTTPS endpoint:
https://your-public-ip/
GitHub repository:
https://github.com/your-github-username/internee-ec2-https
Scope note: this is the verified cloud infrastructure and HTTPS deployment path. The actual Internee.pk application source was not available, so I am not presenting the application itself as migrated.
#AWS #EC2 #Linux #Nginx #HTTPS #LetsEncrypt #CloudComputing
Confirm LinkedIn access
Publishing the evidence requires an account that can reach the post composer. Choose the path that matches your current LinkedIn access.
✔️ I can sign in
- Go to LinkedIn in your browser.
- Sign in to your existing account.
- Confirm that the home feed shows Start a post.
Your existing account is ready to publish the project evidence.
ⓧ I need an account
- Open LinkedIn's official sign-up instructions.
- Enter your name in the prompted field.
- Enter your email address in the prompted field.
- Select Join now.
- Complete the remaining prompted profile setup.
- Confirm that the home feed shows Start a post.
You now have access to the post composer required for the public project summary.
Publish and verify the public post
The repository contains the reusable draft. The published version needs your real endpoint and repository address so reviewers can test the result.
Keep both destinations public
The endpoint demonstrates the running deployment. The repository explains how you built and verified it.
- Select Start a post on the LinkedIn home feed.
- Copy the contents of linkedin-post.txt from your public repository.
- Paste the draft into the What do you want to talk about? field.
- Replace https://your-public-ip/ with https://your-public-ip/.
- Replace https://github.com/your-github-username/internee-ec2-https with https://github.com/your-github-username/internee-ec2-https.
- Open Post settings.
- Choose the public audience option.
- Select Post.
Your project summary should now appear with the live HTTPS endpoint and public repository URL.
- Use the post's sharing control to copy its public URL.
- Record the post URL here: your public LinkedIn post URL.
Can reviewers open the links?
- Confirm that the post uses the public audience option.
- Check that both shared URLs begin with https://.
- Confirm that the GitHub repository visibility remains Public.
Help me troubleshoot why my LinkedIn project post or one of its shared links is not publicly accessible.
Before you check the signed-out views, do you expect every evidence file and shared link to remain visible without your accounts?
- Open a private browser window.
- Load https://github.com/your-github-username/internee-ec2-https in the private window.
- Open a second private browser tab.
- Load your public LinkedIn post URL in the second tab.
You should see the repository documentation and LinkedIn project summary without signing in. Both views should contain working URLs without exposing a private key, certificate private key, or account credential.
That closes the evidence gap. Reviewers can now inspect the deployment decisions and test the trusted HTTPS result for themselves.
Secret mission
Add a Health Check Endpoint
Extend your trusted HTTPS deployment with a machine-readable `/health` route. A monitoring check receives plain-text `ok`. Visitors continue to see the full migration proof at `/`.
Clean Up Your Resources
Clean Up Your Resources
Choose whether to keep this deployment live, pause it for later, or delete it entirely. The AWS Free Plan prevents out-of-pocket charges while active, but eligible usage continues consuming credits.
Cost Warning
The AWS Free Plan incurs no charges unless you upgrade to a Paid Plan or activate paid-only services. Eligible usage still consumes credits.
The plan ends after six months or when its credits are fully used.
After coverage ends, Amazon EC2 compute can incur standard charges. Amazon EBS storage can also incur charges.
A public IPv4 address has a list price of $0.005 per hour. The Pause and Delete options below stop ongoing compute usage.
Resources you used:
- One Amazon EC2 instance named internee-https-proof.
- One root EBS volume containing the website files, server configuration, certificate files, and renewal hook.
- One auto-assigned public IPv4 address attached to the running instance.
- One EC2 security group that restricts SSH access and permits public web traffic.
- One selected or newly created EC2 key pair.
- One Let's Encrypt certificate lineage named internee-ip. Its executable Nginx renewal deploy hook is stored on the instance.
- One public GitHub repository named internee-ec2-https.
- One public LinkedIn project post.
Keep everything running
No action is needed. Choose this option while reviewers still need the live deployment and trusted HTTPS endpoint.
- Keep internee-https-proof running so its auto-assigned public IPv4 address stays attached.
- Monitor your AWS Free Plan credit balance for continued usage.
- Retain the existing security group rules so the website and certificate renewal workflow remain reachable.
- Retain the public internee-ec2-https repository as deployment evidence.
- Leave the LinkedIn post published so reviewers can open the live endpoint.
Keep the IP Stable
The auto-assigned public IPv4 address stays attached while the instance remains running. Keeping that address preserves the certificate match and every shared URL.
Pause - I'll come back to this later
Stopping the instance reduces compute usage while preserving its root EBS volume. The auto-assigned public IPv4 address is released when the instance stops.
- Capture any final live-endpoint evidence before pausing the instance.
- Select internee-https-proof in the Amazon EC2 console.
- Open the Instance state controls.
- Choose Stop instance.
- Confirm the stop request when prompted.
Your SSH session closes when the instance stops. The public endpoint also goes offline.
Returning Later
A restarted instance receives a new public IPv4 address. The existing certificate no longer matches that endpoint.
- Start internee-https-proof from its instance state controls.
- Repeat the certificate issuance workflow for the new public IPv4 address.
- Update the live HTTPS URL in README.md.
- Update the live HTTPS URL in the LinkedIn post.
Delete - I don't want to use this again
Deleting the deployment is permanent, so capture your final evidence first. This option removes the live endpoint and its server-side data.
Terminate the host:
- Capture your final deployment evidence before deleting anything.
- Select internee-https-proof in the Amazon EC2 console.
- Confirm that the root EBS volume is set to delete on termination.
- Open Instance state.
- Choose Terminate (delete) instance.
- Confirm the termination request when prompted.
- Wait until Amazon EC2 reports that the instance is terminated.
What Termination Removes
Termination releases the auto-assigned public IPv4 address. The root EBS volume is removed when its delete-on-termination setting is enabled.
Deleting the volume also removes the website files, Nginx configuration, internee-ip certificate lineage, and renewal deploy hook.
Remove the project security group:
- Open Security Groups under Network & Security in Amazon EC2.
- Select the security group created for internee-https-proof.
- Choose Actions.
- Choose Delete security groups.
- Confirm the deletion when prompted.
Remove a project-only key pair:
- Open Key Pairs under Network & Security in Amazon EC2.
- Select the key pair only if you created it solely for this project.
- Choose Actions.
- Choose Delete.
- Confirm the deletion when prompted.
Delete the public GitHub repository:
- Open the internee-ec2-https repository on GitHub.
- Select the Settings tab.
- Select General in the repository settings sidebar.
- Scroll to Danger Zone.
- Select Delete this repository.
- Complete the repository confirmation prompt.
Delete the public LinkedIn post:
- Open the published project post on LinkedIn.
- Select More in the post controls.
- Select Delete post.
- Confirm the deletion when prompted.
Nice Work!
Nice Work!
You did it! Your Internee.pk infrastructure proof now runs on Amazon EC2 at a browser-trusted HTTPS endpoint.
What you learned:
- Launched a Free Tier-eligible Ubuntu Server host on Amazon EC2. Restricted SSH access to your current public IP. Opened the public web ports needed for the deployment.
- Published the Internee.pk migration page through Nginx. Observed the missing-HTTPS failure before issuing a Let's Encrypt certificate for the public IPv4 address. Configured HTTP redirection to the trusted HTTPS endpoint.
- Automated certificate renewal with an executable Nginx reload hook. Published sanitized deployment evidence through GitHub and LinkedIn without exposing private keys.
- Secret Mission: Added an exact-match /health endpoint that returns only ok as plain text. Monitoring tools can now check server health without loading the full page.
Ready to quiz yourself?