lavenderguitar
3 years ago
commit
7b338b223d
2 changed files with 132 additions and 0 deletions
@ -0,0 +1,5 @@ |
|||
.envrc |
|||
.vault_pass |
|||
*.tfstate |
|||
*.tfstate.backup |
|||
.terraform* |
@ -0,0 +1,127 @@ |
|||
Linode Static Site Infrastructure |
|||
=============== |
|||
|
|||
This repo provides the Terraform and Ansible configuration for generating and hosting static-sites using [Linode](https://linode.com). |
|||
|
|||
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, use the following commands to connect Terraform to the Linode account: |
|||
|
|||
echo "export TF_VAR_token=<<linode_account_api_token>>" >> .envrc |
|||
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)._** |
|||
|
|||
<br> |
|||
|
|||
|
|||
### 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. |
|||
|
|||
<br> |
|||
|
|||
### 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._ |
Loading…
Reference in new issue