A learning journey


Immutable Deployments for Static Sites using Linode CLI

This article describes how the Linode CLI can help us achieve immutable deployments of static websites in the context of an automated CI/CD process. We´ll go through four steps, however, the process can vary depending on each team’s dynamics.

1. Get the site code and create the build artifact

During the first step the goal is to generate the static assets that will be deployed; we download the latest version of the code (most likely stored in a version control repository) and create the build artifact using tools like npm or gulp, obtaining all the required dependencies. This is done in a fresh environment folder, meaning no previous build is stored. 

Although not described here, executing the corresponding unit tests before creating the build is recommended; it’s also a common quality gate for many applications.

Step 2. Create a bucket 

Here we leverage the Linode SDK with the Object Storage plugin, called obj

linode obj [command]

where [command] will be the operation we want to execute. (You can find the usage guide here)

The immutability comes from creating a new bucket each time we deploy. This kind of task is usually done with CI/CD pipeline automated tools, like Jenkins, Azure DevOps, Gitlab, etc., where we can get information about the process execution that changes (increments) every time it runs. For Jenkins, it’d be something like

linode obj mb $BUILD_TAG 

This will help us get a unique (incremental) name each time we execute. Of course, we need to be mindful of the bucket naming restrictions:

  • It must be between 3 and 63 characters in length.
  • It can only contain lower-case characters, numbers, periods, and dashes.
  • It must start with a lowercase letter or number.
  • It cannot contain underscores (_), end with a dash (-) or period (.), have consecutive periods (.), or use dashes (-) adjacent to periods (.).
  • It cannot be formatted as IP addresses.

Our bucket will be created immediately. Next, we want to mark it as a static website using

linode obj ws-create $BUILD_TAG --ws-index=index.html --ws-error=404.html 

Notice we’re using the same variable for the bucket name ($BUILD_TAG), making this process automated and repeatable using our CI/CD tool.

Step 3. Deploy our content

With the s3cmd tool we copy our website content recursively using the sync command

s3cmd --no-mime-magic --acl-public  sync . s3://$BUILD_TAG 

We’re using the following parameters:  

  • no-mime-magic: Tells Object Storage not to use file signatures when guessing the object’s MIME type.
  • acl-public: Sets the access level control of the objects to “public.” This makes our website usable.

(Here’s an S3cmd guide)

At this point, we have a static website ready. We can access it using the URL, which has the following format


In this example, BUCKET_NAME equals $BUILD_TAG, meaning that we can construct the URL dynamically to use it further in the process, like running UI Tests using Puppeteer, Selenium, etc., depending on the quality gates we want to add to the process. 

Step 4. Cleanup 

Once our work is done, we want to eliminate our bucket so we don’t end up with tons of unused objects and ensure they don’t get reused by mistake. We use an empty folder for this; in this case, we create it during the pipeline execution since the process runs on a fresh environment folder each time.

mkdir clean

cd clean

then we use s3cmd sync again

s3cmd --delete-removed --delete-after --force sync . s3://$BUILD_TAG 

Notice we’re using different parameters 

  • delete-removed: Deletes any destination objects with no corresponding source file.
  • delete-after: Deletes destination files no longer found at the source after all files are uploaded to the bucket.
  • force: Confirm we’re syncing an empty folder, resulting in all existing files being deleted.

We need to do this since we cannot remove buckets that aren’t empty. Once completed, we delete the bucket using the Linode CLI again

linode obj rb $BUILD_TAG 


The proposed process aims to facilitate the testing of static websites, which is useful when companies have separate teams for the front and back-end pieces of an application. This can also help teams working with the micro-frontend pattern, where small independent UI chunks are merged as if they were a single one. 

The point here is to illustrate how the Linode CLI can be used to automate tasks of the software development lifecycle. The implementation will vary depending on team composition, practices, and tools. 

Leave a Reply

Your email address will not be published. Required fields are marked *