My guide is largely based on the Deploying to Amazon S3 guide from Semaphore, but with some pre-requisite steps and fine-tuning to S3.

Switching your DNS provider for your domain to Amazon’s Route 53 may be a requirement. Depending on your DNS provider, your DNS configuration, and your willingness to jump through hoops like setting up a reverse proxy on another server, you may be forced to transfer your domain. You should absolutely read the DNS and hosting section of Amazon’s Static Website Using a Custom Domain guide before proceeding.

Before following the Semaphore guide, check out Writing IAM Policies: How to Grant Access to an Amazon S3 Bucket and An Example Walkthrough: Using user policies to control access to your bucket in order to better understand and implement more granular AWS authorization and access.

You should also read the Example: Setting Up a Static Website Using a Custom Domain guide.

Create Buckets

AWS Web Console -> S3 -> Create Bucket -> enter the domain of your site for the bucket name. In my case it is

I prefer to use the domain of my site for the bucket name. It makes things much simpler if you follow a similar convention and name buckets to reflect site domains.

Save these changes.

Select the bucket -> Properties -> Static Website Hosting. Note the Endpoint. In my case, it is

We will need that URL later.

Select the option to Enable website hosting -> Save.

Since I plan to serve my site at, I want to redirect requests from www to the root domain.

AWS Web Console -> S3 -> Create Bucket ->

Select the bucket -> Properties -> Static Website Hosting -> Redirect all requests to another host name -> Redirect all requests to should be set to the desired domain. In my case it is Save these changes.

Create User

AWS Web Console -> Security Credentials -> Users -> Create New Users. Make sure that Generate an access key for each user is checked.

Use semaphore-user-THE_DOMAIN_OF_YOUR_SITE as your username, or some other variant. I prefer having a separate user for each site in Semaphore that I will deploy to S3. That way, if one account is compromised, it will not result in risking other sites.

In my case, the username is

After creating the account, Show User Security Credentials and record that information someone secure!

Note: For some odd reason, my downloaded credentials file added a % suffix. Might have just been something odd on my machine, but be on the lookout if you encounter any issues getting Semaphore to authenticate later on. I thought the % was part of the credentials at first, and wasted some time with that.

Create Group

AWS Web Console -> Security Credentials -> Groups -> Create New Group. Again, I prefer to use a name like semaphore-group-THE_DOMAIN_OF_YOUR_SITE.

In my case that would be I know, it is a bit redundant to put group in the name, but I’d rather be explicit and verbose. These names will rarely be used, so I am not too concerned about them being long.

Do not grant any permissions to the group. Instead, click Next Step and Create Group.

Add Users to Group

AWS Web Console -> Security Credentials -> Groups. Click on the name of your group. In my case, it is

Users -> Add Users to Group. Select your user. In my case, it is Click Add Users.

You may be wondering why we need a group with only one user. As the AWS docs mention in Creating an IAM User in Your AWS Account, “We recommend using groups rather than attaching policies directly to users.”

Create Policy

AWS Web Console -> Security Credentials -> Policies -> Create Policy -> Create Your Own Policy.

Follow the same pattern to create the Policy Name like semaphore-policy-THE_DOMAIN_OF_YOUR_SITE. In my case it is

You may leave the Description blank, but enter the following information for the Policy Document.

Note, that date in the Version cannot be altered. It is not a customizable version number, but rather an AWS defined value.

Replace in the policy with the domain of your site.

	"Version": "2012-10-17",
	"Statement": [
			"Effect": "Allow",
			"Action": [
			"Resource": "arn:aws:s3:::*"
			"Effect": "Allow",
			"Action": "s3:*",
			"Resource": [

This policy allows a group to list all of the buckets to which it has access, which is required for Semaphore. It also grants full access to the bucket used for the site.

Attach Policy to Group

AWS Web Console -> Security Credentials -> Groups. Click on the name of your group. In my case, it is

Permissions -> Attach Policy. Filter for the policy you just created it. In my case it is Select it, and Attach Policy.

Set Up Deployment in Semaphore

At this point, you should be able to follow the Semaphore guide from the Setting Up the Website section.

Here is my abridged version of the process.

Projects -> Your Site -> Severs (+) -> AWS S3 -> Automatic -> enter your AWS Access Key ID and AWS Secret Access Key. Select a region for your S3 bucket.

If deploying a jekyll blog (like I am) you can specify public as the Content to be deployed to S3.

That means that Semaphore will deploy only the generated files, and not the source code, which would be ideal.

Leave the S3 Index Document as index.html and select the S3 Bucket, which would be in my case.

Name Your Server with something meaningful. I feel like S3 sums up the deployment method well enough.

Set the Server URL (optional) using the Endpoint found above in S3. In my case it is

Finish the wizard to confirm these settings and initiate the first deployment.


Depending on your configuration, you may need to switch hosting of your domain for your blog to Amazon’s Route 53.

You should absolutely read and understand the Example: Setting Up a Static Website Using a Custom Domain guide and the Migrating DNS Service for an Existing Domain to Amazon Route 53 guide.

The technical details behind your DNS hosting may vary greatly from mine, so I will not add any more information on this step.