lavenderguitar
6f75fec8a2
|
3 years ago | |
---|---|---|
ansible | 3 years ago | |
jekyll-site | 3 years ago | |
terraform | 3 years ago | |
.gitignore | 3 years ago | |
README.md | 3 years ago |
README.md
Linode Static Site Infrastructure
This repo provides the Terraform and Ansible configuration for generating and hosting static-sites using Linode.
The infrastructure inside Linode will consist of two application instances served behind a NodeBalancer. These instances will have external IPs used to configure and deploy to them. Linode Firewalls in combination with UFW are used to limit access to them.
On the instances themselves, an administrative user and deploy user are created (as well as a user for Caddy). Caddy is used as the web-server in order to accommodate automatic-HTTPS of each site.
The jekyll site provided in this repo is an example and includes the necessary Capistrano configuration to perform deploys.
Hint: If configured properly using the provided setup, a different set of static sites can be served to multiple domains from the same set of app instances.
Using the repo
Initialize Linode Infrastructure - Terraform
First, clone the repo. Then cd terraform/
. From here, create a .envrc
file to load a few custom variables into your shell using direnv
:
export TF_VAR_token=TF_VAR_token=<<linode_account_api_token>>
export TF_VAR_root_pass=<<randomly_generated_root_pass_for_all_instances>>
export AWS_ACCESS_KEY_ID=<<linode_object_storage_access_key>>
export AWS_SECRET_ACCESS_KEY=<<linode_object_storage_secret_access_key>>
Replace the name and region names in terraform/backend.tf
to match the bucket created to store the .tfstate file.
Use direnv
to load the vars and Terraform to the Linode account:
echo "export TF_VAR_token=<<linode_account_api_token>>" >> .envrc ## Add this manually, don't put a token in a CLI history.
direnv allow
terraform init
Once Terraform has been initialized, set the appropriate variables for the desired infrastructure in site.auto.tfvars
:
site = "example.com"
region = "us-southeast"
environment = "production"
app_servers = [
{
type = "g6-nanode-1"
image = "linode/ubuntu20.04"
},
{
type = "g6-nanode-1"
image = "linode/ubuntu20.04"
}
]
bastion_server = {
type = "g6-nanode-1"
image = "linode/ubuntu20.04"
}
ssh_key = "~/.ssh/id_rsa.pub"
After filling in the variables, use terraform plan
to ensure the proper infrastructure will be generated. terraform apply
will generate the infrastructure.
Upon completion, terraform apply
will supply the IPv4 addresses of the NodeBalancer, as well as the site instances:
Outputs:
linode_instance_ip_address = [
toset([
"192.168.232.187",
"45.79.216.88",
]),
toset([
"192.168.144.144",
"45.79.216.70",
]),
]
nodebalancer_ip_address = "45.79.245.251"
Use the NodeBalancer IP address to set the DNS A record for the website(s).
Configure Application VMs - Ansible
Once the infrastructure has been created, cd to the ansible/
directory. From here, we'll set a few inventory variables, and the IP addresses of the hosts.
In inventories/production/hosts
set the IP address of each instance created. Use the external IP addresses provided by the terraform output.
Using inventories/production/group_vars/all
, set the variables for the site in /common-main.yml
and /main.yml
:
## main.yml
# Website/Blog settings
domain: "example.com"
staging_domain: "staging.example.com"
site_name: "site"
## common-main.yml
ruby_version: '2.7'
bundler_version: '2.1.4'
ssh__keys:
- key: ssh-key-of-the-deployer
After setting these variables appropriately for your project, use the site.yml
playbook to install the configuration.
ansible-playbook site.yml -i inventories/production/hosts --diff
Since this is the first time running the playbook on the instances, we won't be using --check as we need to install python first
Using the defaulted configuration will result in a few convenient settings:
- A staging site is served at
/srv/{{site_name}}-staging/
- A production site is served at
/srv/{{site-name}}/
- A
jekyll
user can be used for deploys. - An
ops
user exists to perform administrative actions as needed.
Deploy a site with Jekyll
A default Jekyll site exists in the /jekyll-site
repo. This site will use Capistrano for deploys to the instances.
Navigate to the jekyll-site directory.
First, look in config/deploy.rb
and set the ssh url of the repository storing the site.
Set the app instance IP addresses in config/production.rb
and config/staging.rb
. Additionally, ensure the deploy_to
directories match the deploy directories set in the Ansible configuration.
From here, use Capistrano to deploy the site to the instances:
bundle exec cap production deploy --trace
--dry-run
can be used to test the deploy
Wrapping up
If all the steps have been completed, the instances should be serving their static site content at the specified domains. To make the infrastructure even more secure, we can take a few additional steps to secure different aspects from the initial build.
First, navigate to terraform/firewall.tf
. In this file, remove the inbound rules for port 22
. Since we have changed the default port to 8822
we can now close the traffic to this port completely. apply
this change to the firewall.
Second, navigate to ansible/inventories/production/hosts
. Notice that the ansible_user
is set as root
and the ansible_port
is 22
. Change the port to 8822
and the user to the specified admin user (default: ops
). Root is used for initial ansible run as Linode only provides root access to start. After initial run is complete, port 22 is closed.