# Terraform: Mount S3 Bucket on EC2 (Ubuntu) using s3fs‑fuse 

## **Introduction**

Amazon continues to blur the lines between object storage and traditional file systems. With the launch of Amazon S3 Files, working with S3 becomes far more intuitive for engineers who prefer file system semantics over API-driven operations. This project automates the creation of an S3 bucket, an EC2 instance (Ubuntu 22.04), an IAM role with S3 permissions, and the automatic mounting of the bucket as a local file system using s3fs‑fuse. It uses Terraform to provision the infrastructure and a user‑data script to configure the mount on the instance.

## 📖 Overview

When you need to access S3 objects as if they were local files (e.g., for legacy applications, log processing, or shared storage), s3fs‑fuse is a reliable solution. This repository provides a complete, production‑ready Terraform setup that:

Creates an S3 bucket with versioning enabled (optional) and public access blocked.

Launches an Ubuntu 22.04 LTS EC2 instance with a public IP.

Attaches an IAM role that grants read/write access to the bucket.

Installs s3fs‑fuse and mounts the bucket to /mnt/s3-bucket automatically on startup.

Adds an entry to /etc/fstab to persist the mount across reboots.

All resources are tagged, well‑structured, and easy to destroy when no longer needed.

## 🗂️ Project Structure

├── [provider.tf](http://provider.tf) # Terraform and AWS provider configuration

├── [variables.tf](http://variables.tf) # Input variables (bucket name, key name, region, etc.)

├── terraform.tfvars # (create yourself) – actual variable values

├── [data.tf](http://data.tf) # Ubuntu 22.04 AMI lookup

├── [s3.tf](http://s3.tf) # S3 bucket, versioning, and public access block

├── [iam.tf](http://iam.tf) # IAM role, policy, and instance profile

├── [security-groups.tf](http://security-groups.tf) # Security group (SSH and HTTP access)

├── [ec2.tf](http://ec2.tf) # EC2 instance + Elastic IP (optional)

├── [userdata.sh](http://userdata.sh) # Script to install s3fs and mount the bucket

├── [outputs.tf](http://outputs.tf) # Public IP, DNS, bucket name, mount point

└── [README.md](http://README.md) # This file 🧰 Prerequisites Terraform (≥ 1.0)

AWS CLI configured with credentials having permissions to create EC2, S3, IAM, and security groups.

An existing EC2 key pair in your AWS account (for SSH access).

Basic knowledge of AWS and Terraform.

## ⚙️ Setup & Deployment

Clone the repository

```plaintext
git clone https://github.com/joebaho2/S3-FILES-TF.git 
```

```plaintext

cd S3-FILES-TF
```

Create terraform.tfvars

Create a file named terraform.tfvars with your specific values:

```plaintext
aws_region = "us-west-2" 

bucket_name = "my-unique-bucket-name-12345"         # must be globally unique 

key_name = "your-existing-key-pair-name" 

instance_type = "t2.micro"                 # free tier eligible 

mount_point = "/mnt/s3-bucket"            # customise if needed 
```

Initialize Terraform

```plaintext
terraform init 
```

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/a77e87d0-cc06-4ca9-a102-84d6e244860e.png align="center")

Validate the quality and the configuration syntax of the code with commands

```plaintext
terraform fmt 

terraform validate
```

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/90de303d-ae61-4225-a03b-75a8c5eff145.png align="center")

Review the plan

```plaintext
terraform plan 
```

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/2be290a9-2642-43c3-b53a-e21d9672f481.png align="center")

Apply

```plaintext
terraform apply -auto-approve 
```

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/c428cfa3-3e7a-4b6b-b5a8-927df957dac8.png align="center")

Go back to console to see all resources created ec2 instance and s3 bucket

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/d88efac9-b176-4dcb-bd7b-6d06eddf2f6d.png align="center")

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/6c1c085c-8230-4707-aa3d-5effdfb98115.png align="center")

After completion, Terraform outputs the public IP, bucket name, and mount point.

Connect to the instance \`

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/190a5d5c-baf6-4724-a5b2-eea8ff797eea.png align="center")

ssh -i your-key.pem ubuntu@$(terraform output -raw instance\_public\_ip)

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/31221196-2926-4aa4-b274-29f8b66acee4.png align="center")

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/bc703ec7-7f28-4cab-9c94-8f2ebb47b69c.png align="center")

Verify the mount

```plaintext
df -h | grep s3fs ls -la /mnt/s3-bucket 
```

```plaintext
echo "Hello from EC2" | sudo tee /mnt/s3-bucket/test.txt 
```

You can now read and write files -they are directly stored in S3

The previous command created a files test.txt and was sent directly to the S3 files system via cli

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/40fe1e4f-b77c-4953-bd79-37b2c02d917c.png align="center")

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/44519274-cc16-41a0-aa77-54c5d52292c8.png align="center")

You can also upload file via the console and check status via cli

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/872008d7-feeb-438c-8794-283e62cb0ebe.png align="center")

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/89e3d000-cffa-41bc-b73b-96ce94c01b79.png align="center")

### 🧼 Clean Up

### To prevent ongoing charges, destroy all resources.

```plaintext
terraform destroy -auto-approve 
```

![](https://cdn.hashnode.com/uploads/covers/6605b33d2b011c6238012384/c5735704-35d1-48a5-ac71-8d4dcd524466.png align="center")

Note: The S3 bucket is configured with force\_destroy = true. This will delete all objects and versions inside the bucket before removing the bucket itself. Use with caution – data cannot be recovered.

## 🛠️ Customisation

Variable Description Default

aws\_region AWS region us-west-2

bucket\_name Unique S3 bucket name (required)

key\_name EC2 key pair name (required)

instance\_type EC2 instance type t2.micro

mount\_point Local directory for the mount -/mnt/s3-bucket

You can also adjust the security group ingress rules in security-groups.tf (e.g., restrict SSH to your IP).

## 🔧 Troubleshooting

The mount point is empty or the bucket is not mounted Check the user‑data script logs on the instance:

```plaintext
sudo cat /var/log/cloud-init-output.log Manually install s3fs and mount:
```

Manually install s3fs and mount

```plaintext
sudo apt update && sudo apt install -y s3fs sudo s3fs /mnt/s3-bucket -o allow_other,use_cache=/tmp,iam_role=auto 
```

Verify the IAM role is attached to the instance (AWS Console → EC2 → Instance → IAM role = EC2S3AccessRole).

Terraform destroy fails because bucket is not empty . The s3.tf file includes force\_destroy = true. If you removed it, manually empty the bucket first:

```plaintext
aws s3 rm s3:// --recursive 
```

Permission denied when writing to mount point Ensure the ubuntu user has write permissions:

```plaintext
sudo chmod 777 /mnt/s3-bucket # not recommended for production
```

## **🤝 Contributing**

Your perspective is valuable! Whether you see potential for improvement or appreciate what's already here, your contributions are welcomed and appreciated. Thank you for considering joining us in making this project even better. Feel free to follow me for updates on this project and others, and to explore opportunities for collaboration. Together, we can create something amazing!

## **📄 License**

This project is licensed under the JoebahoCloud License
