diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75754f8852f..f6977c6af98 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,23 +50,35 @@ Use [Chocolatey](https://chocolatey.org/) to install Hugo on Windows: This section takes you through the process of creating a new guide using the topic of installing nginx on Debian as an example. You can use a [Hugo archetype](https://gohugo.io/content-management/archetypes/) to simplify the process. -1. Create a new branch for your guide: +1. Checkout the develop branch: + + git checkout develop + +2. Update the develop branch with the latest changes. If this is the first time creating a new guide, you will have to first add the docs repository as a remote: + + git remote add upstream https://github.com/linode/docs.git + + Update the develop branch: + + git pull upstream develop + +3. Create a new branch for your guide: git checkout -b nginx-on-debian -2. From the root of the `docs` repo, run the following command. Specify the location and title of your guide; the example nginx guide should be located in `web-servers/nginx`. This will create a markdown file populated with YAML front matter: +4. From the root of the `docs` repo, run the following command. Specify the location and title of your guide; the example nginx guide should be located in `web-servers/nginx`. This will create a markdown file populated with YAML front matter: hugo new web-servers/nginx/how-to-install-nginx-on-debian/index.md --kind content - This will create a subdirectory with the guide's intended url, with an `index.md` file inside that will hold the guide's contents. Any images should be added inside this directory as well. + This will create a subdirectory with the guide's intended url, with an `index.md` file inside that will hold the guide's contents. Any images should be added inside this directory as well. -3. Start the Hugo server: +5. Start the Hugo server: hugo server This starts a local server you can use to view the Linode library in your browser on `http://localhost:1313/docs/`. -4. In a web browser, navigate to the location of your new guide. The example nginx guide will be located at `http://localhost:1313/docs/web-servers/nginx/how-to-install-nginx-on-debian`. +6. In a web browser, navigate to the location of your new guide. The example nginx guide will be located at `http://localhost:1313/docs/web-servers/nginx/how-to-install-nginx-on-debian`. ## Run Tests diff --git a/ci/vale/dictionary.txt b/ci/vale/dictionary.txt index d3c37d5236c..d5fac73515f 100644 --- a/ci/vale/dictionary.txt +++ b/ci/vale/dictionary.txt @@ -915,6 +915,7 @@ pagent pagespeed pandoc param +parameterizing paramiko parallelization params @@ -1273,6 +1274,7 @@ tcp tcpwrappers teamspeak tensorflow +terrahelp terraria testdb testfile diff --git a/ci/yaml_rules.json b/ci/yaml_rules.json index 5875e8c8aa6..0d51ec8cd4c 100644 --- a/ci/yaml_rules.json +++ b/ci/yaml_rules.json @@ -5,6 +5,12 @@ "type": "list", "description": "Other locations where this guide can be found. Should be an array of entries in the form /applications/big-data/using-big-data/" }, + "audiences": { + "elements": false, + "required": false, + "type": "list", + "description": "An array of audiences. Could be Foundational, Beginner, Intermediate, or Expert" + }, "author": { "elements": [ "name", @@ -20,6 +26,12 @@ "type": "text", "description": "In a guide written for the current Linode Manager, if a new version of the guide exists written for the new Linode Manager, use this in the original guide to embed a link to the new guide. Must use alias-style relative links (e.g. platform/manager/dns-manager-cloud-manager/)." }, + "concentrations": { + "elements": false, + "required": false, + "type": "list", + "description": "A list of development section concentrations. Case sensitive, capitalize words where appropriate. Could be one of: 'Scripting, Automation, and Build Tools', 'Web Applications', 'Unit Testing', or 'Scientific Computing and Big Data'" + }, "h1_title": { "elements": false, "required": false, @@ -100,6 +112,12 @@ "type": "text", "description": "If a layout other than the default is needed (i.e. for the Contribute page), specify the name of the layout here." }, + "languages": { + "elements": false, + "required": false, + "type": "list", + "description": "An array of programming languages that apply to the guide. Could be JavaScript, Go, Python, etc." + }, "license": { "elements": false, "required": true, diff --git a/config.toml b/config.toml index 96ca54325ec..cef8fe1326b 100644 --- a/config.toml +++ b/config.toml @@ -20,10 +20,11 @@ pygmentsStyle = "perldoc" disqusShortname="linode-1" -disableKinds = ["taxonomy", "taxonomyTerm"] +#disableKinds = ["taxonomy", "taxonomyTerm"] rssLimit = 15 + [blackfriday] fractions = false @@ -33,7 +34,9 @@ section = ["HTML"] page = ["HTML"] [taxonomies] -category = "categories" +audience = "audiences" +concentration = "concentrations" +language = "languages" [params] description = "Guides and tutorials on the Linode platform, Linux basics, and software installation and configuration." @@ -50,7 +53,7 @@ time_format_default = "Monday, January 2, 2006" # threshold = 80 # includeNewer = true # toLower = false -# +# # [[related.indices]] # name = "keywords" # weight = 100 diff --git a/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/Store_and_Share_your_Files_with_Nextcloud_on_Centos_smg.png b/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/Store_and_Share_your_Files_with_Nextcloud_on_Centos_smg.png new file mode 100644 index 00000000000..37aaaa8253c Binary files /dev/null and b/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/Store_and_Share_your_Files_with_Nextcloud_on_Centos_smg.png differ diff --git a/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/index.md b/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/index.md index 25e9c0909db..7aaecda9ba5 100644 --- a/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/index.md +++ b/docs/applications/cloud-storage/store-and-share-your-files-with-nextcloud-centos-7/index.md @@ -6,7 +6,7 @@ description: "Nextcloud is an open source solution to hosting your own content o keywords: ["nextcloud", "cloud", "open source hosting"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' published: 2017-12-15 -modified: 2017-12-15 +modified: 2018-12-18 modified_by: name: Linode title: 'Store and Share your Files with Nextcloud on Centos 7' @@ -19,6 +19,8 @@ external_resources: - '[Enabling SSL](https://docs.nextcloud.com/server/12/admin_manual/installation/source_installation.html#enabling-ssl)' --- +![Store and Share your Files with Nextcloud on CentOS](Store_and_Share_your_Files_with_Nextcloud_on_Centos_smg.png "Store and Share your Files with Nextcloud on CentOS") + ## Before You Begin 1. Familiarize yourself with our [Getting Started](/docs/getting-started/) guide and complete the steps for setting your Linode's hostname and timezone. diff --git a/docs/applications/configuration-management/create-a-nodebalancer-with-terraform/index.md b/docs/applications/configuration-management/create-a-nodebalancer-with-terraform/index.md new file mode 100644 index 00000000000..e0355301e8c --- /dev/null +++ b/docs/applications/configuration-management/create-a-nodebalancer-with-terraform/index.md @@ -0,0 +1,288 @@ +--- +author: + name: Linode + email: docs@linode.com +description: 'How to create a NodeBalancer and Nodes with Terraform.' +keywords: ['terraform','nodebalancer','node','balancer','provider','linode'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-12 +modified: 2018-12-12 +modified_by: + name: Linode +title: "Create a NodeBalancer with Terraform" +contributor: + name: Linode +external_resources: +- '[Terraform Linode Provider Reference](https://www.terraform.io/docs/providers/linode/index.html)' +- '[linode_nodebalancer Resource Reference](https://www.terraform.io/docs/providers/linode/r/nodebalancer.html)' +- '[linode_nodebalancer_config Resource Reference](https://www.terraform.io/docs/providers/linode/r/nodebalancer_config.html)' +- '[linode_nodebalancer_node Resource Reference](https://www.terraform.io/docs/providers/linode/r/nodebalancer_node.html)' +- '[linode_instance Resource Reference](https://www.terraform.io/docs/providers/linode/r/instance.html)' +- '[Terraform Random Provider Reference](https://www.terraform.io/docs/providers/random/index.html)' +- '[Terraform Built-In Function Reference](https://www.terraform.io/docs/configuration/interpolation.html#supported-built-in-functions)' +--- + +Terraform allows you to represent Infrastructure as Code (IaC). You can use it to manage infrastructure, speed up deployments, and share your infrastructure's configuration files within a team. In this guide you will use Terraform to create a NodeBalancer that distributes traffic between two Linodes. + +{{< caution >}} +The configurations and commands used in this guide will result in multiple billable resources being added to your account. Be sure to monitor your account closely in the Linode Manager to avoid unwanted charges. See the [Billings and Payments](/docs/platform/billing-and-support/billing-and-payments-new-manager/) guide for more details. + +If you would like to stop billing for the resources created in this guide, [remove them](#optional-remove-the-nodebalancer-resources) when you have finished your work. +{{< /caution >}} + +## Before You Begin + +1. You should have Terraform installed in your development environment, and have a working knowledge of Terraform resource configuration and the [Linode provider](https://www.terraform.io/docs/providers/linode/index.html). For more information on how to install and use Terraform, check out our [Use Terraform to Provision Linode Environments](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/) guide. + +1. Terraform requires an API access token. Follow the [Getting Started with the Linode API](/docs/platform/api/getting-started-with-the-linode-api-new-manager/#get-an-access-token) guide to obtain a token. + +1. Create a `terraform_nodebalancer` directory on your computer for the Terraform project you will create in this guide. All files you create in this guide should be placed in this directory, and you should run all commands from this directory. This new project should not be created inside another Terraform project directory, including the one you may have made when previously following [Use Terraform to Provision Linode Environments](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/). + +## Create a Terraform Configuration File + +### Create a Provider Block + +The first step to take when creating a Terraform configuration file is to create a *provider block*. This block lets Terraform know which provider to use. The only configuration value that the Linode provider needs is an API access token. + +Create a file named `nodebalancer.tf` in your Terraform project directory. You will be adding to this file throughout the guide. Add the provider block to the file: + +{{< file "nodebalancer.tf" >}} +provider "linode" { + token = "${var.token}" +} +{{< /file >}} + +This provider block uses variable interpolation to access the value of your API token. You will create input variables in a separate `variables.tf` file later in the [Define Terraform Variables](#define-terraform-variables) section of this guide. Any input variables you define within the `variables.tf` file are available from the `var` dictionary using dot notation. You will be using variable interpolation and referencing variables with dot notation throughout this guide. + +### Create a NodeBalancer Resource + +Create a NodeBalancer resource in the `nodebalancer.tf` file: + +{{< file "nodebalancer.tf" >}} +... + +resource "linode_nodebalancer" "example-nodebalancer" { + label = "examplenodebalancer" + region = "${var.region}" +} + +... +{{< /file >}} + +The `linode_nodebalancer` resource supplies two labels. The first label, `example-nodebalancer`, is used internally by Terraform. The second label, `examplenodebalancer`, is used to reference your NodeBalancer in tools like the Manager and the Linode CLI. The region for this NodeBalancer is supplied with the variable `region`. + +### Create NodeBalancer Config Resources + +In addition to the NodeBalancer resource, you must supply at least one NodeBalancer Configuration resource. This resource defines ports, protocol, health checks, and session stickiness, among other options, that the NodeBalancer might use. For this example, you will create a NodeBalancer configuration for HTTP access on port 80, but you could also create one for HTTPS access on port 443 if you have [SSL/TLS certificates](/docs/security/ssl/install-lets-encrypt-to-create-ssl-certificates/): + +{{< file "nodebalancer.tf" >}} +... + +resource "linode_nodebalancer_config" "example-nodebalancer-config" { + nodebalancer_id = "${linode_nodebalancer.example-nodebalancer.id}" + port = 80 + protocol = "http" + check = "http_body" + check_path = "/healthcheck/" + check_body = "healthcheck" + check_attempts = 30 + check_timeout = 25 + check_interval = 30 + stickiness = "http_cookie" + algorithm = "roundrobin" +} + +... +{{< /file >}} + +The NodeBalancer Config resource requires a NodeBalancer ID, which is populated in the first line with the variable `linode_nodebalancer.example-nodebalancer.id`. Because the `nodebalancer_id` argument references a NodeBalancer that has not been created yet, you can use this variable as a placeholder to reference the NodeBalancer ID. Terraform will automatically know to create the NodeBalancer resource before it creates any other resources that reference it. In this way you can craft intricate infrastructure that references its own parts, without having to worry about the order the resources appear in the Terraform configuration or whether or not the resources already exist. + +As far as settings go, the health check is set to `http_body`, meaning that the health check will look for the string set by `check_body` within the body of the page set at `check_path`. The NodeBalancer will take a node out of rotation after 30 failed check attempts. Each check will wait for a response for 25 seconds before it is considered a failure, with 30 seconds between checks. Additionally, the session stickiness setting has been set to `http_cookie`. This means that the user will continue to be sent to the same server by the use of a session cookie. The algorithm has been set to `roundrobin`, which will sort users evenly across your backend nodes based on which server was accessed last. + +{{< note >}} +Review the [NodeBalancer Reference Guide](/docs/platform/nodebalancer/nodebalancer-reference-guide) for a full list of NodeBalancer configuration options. +{{< /note >}} + +### Create NodeBalancer Node Resources + +The third part of setting up a NodeBalancer in Terraform is creating the NodeBalancer Node resource. This resource contains information about the individual Nodes and how they pertain to the NodeBalancer and NodeBalancer Configuration resources. + +{{< file "nodebalancer.tf" >}} +... + +resource "linode_nodebalancer_node" "example-nodebalancer-node" { + count = "${var.node_count}" + nodebalancer_id = "${linode_nodebalancer.example-nodebalancer.id}" + config_id = "${linode_nodebalancer_config.example-nodebalancer-config.id}" + label = "example-node-${count.index + 1}" + address = "${element(linode_instance.example-instance.*.private_ip_address, count.index)}:80" + mode = "accept" +} + +... +{{< /file >}} + +This resource's `count` argument will be populated with the `node_count` input variable you will define later on in this guide. The `count` argument tells Terraform that it should provision `node_count` number of Nodes. + +Because provisioning more than one node creates a loop in the Terraform process, where the step for creating a node is repeated, you can use the `count.index` variable to keep track of which iteration Terraform is on in the loop. The interpolation `{count.index + 1}` in the node's `label` argument tells Terraform that you'd like each of the nodes to be labeled sequentially, and because `count.index` starts at zero, you'd like the count to begin at one. + +`linode_instance.example-instance.*.private_ip_address` references the private IP addresses of the yet-to-be-created Linode instances. In the next step, the Linode Instance resources will be labeled `example-instance`. Terraform has access to some attributes for each of the resources it creates, and `private_ip_address` is one of the available attributes from a Linode Instance resource. Because there will be two Linode instances created during the same step, Terraform groups these sets of attributes in a list. The `element()` function allows you to grab a single item from a list based on the item index. Here, instead of providing a hard-coded number for the index you can instead provide `count.index`. In this way the first NodeBalancer Node will reference the private IP address of the first Linode instance, and the second NodeBalancer Node will reference the private IP address of the second instance. + +### Create a Linode Instance Resource + +Now that you have the NodeBalancer configured, you need to supply it with a Linode Instance resource. This resource will allow Terraform to know which instances it needs to create to meet the demand of our NodeBalancer example. + +{{< file "nodebalancer.tf" >}} +... + +resource "linode_instance" "example-instance" { + count = "${var.node_count}" + label = "example-instance-${count.index + 1}" + group = "nodebalancer-example" + tags = ["nodebalancer-example"] + region = "${var.region}" + type = "g6-nanode-1" + image = "linode/ubuntu18.10" + authorized_keys = ["${chomp(file(var.ssh_key))}"] + root_pass = "${random_string.password.result}" + private_ip = true + + provisioner "remote-exec" { + inline = [ + # install NGINX + "export PATH=$PATH:/usr/bin", + + "apt-get -q update", + "mkdir -p /var/www/html/", + "mkdir -p /var/www/html/healthcheck", + "echo healthcheck > /var/www/html/healthcheck/index.html", + "echo node ${count.index + 1} > /var/www/html/index.html", + "apt-get -q -y install nginx", + ] + + connection { + type = "ssh" + user = "root" + password = "${random_string.password.result}" + } + } +} + +... +{{< /file >}} + +The above resource uses the same `count` argument as the NodeBalancer Node resource that was configured in the previous step. Also, the `label` argument is being sequentially incremented in a similar fashion to the NodeBalancer Node. + +The `authorized_keys` argument is supplied an SSH key input variable that will be defined later in this guide. It is passed to the `file()` function, which reads the contents of a file into a string. That string is then passed to the `chomp()` function, which strips any extra whitespace. + +`root_pass` is given the result of the `random_string` resource that will be defined later in this guide. + +The last thing of note in this Linode Instance resource is the `remote-exec` Provisioner block. This block contains two other components, the `inline` list and `connection` block. `inline` is a list of commands that Terraform will execute on the Linode instance once the Linode instance has booted. In this example, the inline commands will: update the Linode instance, create the necessary directory structure for NGINX, create the health check file and the more generalized `index.html` file, and install NGINX. + +The `connection` block explains to Terraform how it should gain access to the Linode instance in order to run the commands supplied by the `inline` list. In this case, Terraform will gain access over SSH, logging in as the `root` user. + +### Create an Output + +The last step that you'll take in creating `nodebalancer.tf` is adding an output. Terraform will add this information to the end of it's output in the terminal. Outputs can be any information from your configuration you would like to expose. Below is an example that will display the public IP address of the NodeBalancer: + +{{< file "nodebalancer.tf" >}} +... + +output "NodeBalancer IP Address" { + value = "${linode_nodebalancer.example-nodebalancer.0.ipv4}" +} +{{< /file >}} + +## Define Terraform Variables + +You will now declare all variables required by your Terraform configuration in a `variables.tf` file. + +1. Create a file called `variables.tf`. This file will create the variables referenced in the configuration of your NodeBalancer and Nodes. You will supply values to the variables in another step. + + {{< file "variables.tf" >}} +variable "token" { + description = "Your APIv4 Access Token" +} + +variable "region" { + description = "The datacenter where your NodeBalancer and Nodes will reside. E.g., 'us-east'." + default = "us-west" +} + +variable "node_count" { + description = "The amount of backend Nodes to create." +} + +variable "ssh_key" { + description = "The local file location of the SSH key that will be transferred to each Linode." + default = "~/.ssh/id_rsa.pub" +} + +resource "random_string" "password" { + length = 32 + special = true + upper = true + lower = true + number = true +} +{{< /file >}} + + Terraform allows each variable to have its own description and default value. These variables will have their values populated through the use of a `terraform.tfvars` file that you will create in the next step. Separating the variable definitions from their values helps to keep sensitive data from entering your Terraform code, should you choose to include your code in a version control system like Git. + + In addition to the variables you defined above, there is also a `random_string` resource with the label `password`. This resource is provided by the [Random provider](https://www.terraform.io/docs/providers/random/index.html), and will generate a random string of 32 characters, including uppercase characters, lowercase characters, and numbers. This string will be the root password for your backend Nodes. If you would rather have exact control over your passwords, you can define a password here in `variables.tf` and set the value for that password in `terraform.tfvars` in the next step. + +1. Create the `terraform.tfvars` file and supply values for the `token`, `region`, and `node_count` variables. This example uses the `us-east` regional datacenter, and the `node_count` is two. + + {{< file "terraform.tfvars" >}} +token = "your_api_token" +region = "us-east" +node_count = 2 +{{< /file >}} + + When Terraform runs, it looks for a file named `terraform.tfvars`, or files with the extension `*.auto.tfvars`, and populates the Terraform variables with those values. If your SSH key is at a file location that is different than the default value, i.e., it does not exist at `~/.ssh/id_rsa.pub`, then you will need to add that value to `terraform.tfvars`. + + {{< note >}} +If you want to use an input variable's default value defined in the `variables.tf` file, you can omit providing a value for that variable in the `terraform.tfvars` file. + {{}} + + Feel free to change any of the values in the `terraform.tfvars` file to your liking. For a list of regional datacenter IDs, you can use the cURL command to query the API: + + curl https://api.linode.com/v4/regions + +## Initializing, Planning, and Applying the Terraform State + +Because this guide employs two providers (Linode and Random) that you might not have installed on your local development environment, you'll need to run the `init` command to install them. + + terraform init + +You should see a message that Terraform has been successfully initialized. + +To review the Terraform plan of action defined in the `nodebalancer.tf` file, run the `plan` command: + + terraform plan + +You should see a lengthy output with all the `create` actions that will take place. Review the output, taking note that the `` values you see will be defined on creation. Once you are satisfied with the proposed actions, it's time to apply them. + +Run the `apply` command: + + terraform apply + +You will be prompted to approve the `apply` action. Type *yes* and hit **Enter**. Terraform will begin to create the resources you have configured in the previous steps. This will take a few minutes, after which you will start to see the output of the the `remote-exec` commands you defined in your Linode instance resource. Once all of the actions are completed you should see output like the following: + +{{< output >}} +Apply complete! Resources: 7 added, 0 changed, 0 destroyed. + +Outputs: + +NodeBalancer IP Address = 104.237.148.131 +{{< /output >}} + +Navigate to your NodeBalancer IP address and view your NodeBalancer in action. You have successfully created a NodeBalancer and backend nodes in Terraform. + +### (Optional) Remove the NodeBalancer Resources + +If you are done with the resources you just created, you can remove them with the `destroy` command + + terraform destroy + +This command will prompt you to confirm the action. \ No newline at end of file diff --git a/docs/applications/configuration-management/create-terraform-module/index.md b/docs/applications/configuration-management/create-terraform-module/index.md new file mode 100644 index 00000000000..528798aca01 --- /dev/null +++ b/docs/applications/configuration-management/create-terraform-module/index.md @@ -0,0 +1,598 @@ +--- +author: + name: Linode Community + email: docs@linode.com +description: 'Create a Terraform module that deploys a Linode instance from a StackScript.' +keywords: ['terraform','resource','modules','provider'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-12 +modified: 2018-12-12 +modified_by: + name: Linode +title: "Create a Terraform Module" +contributor: + name: Linode +external_resources: +- '[Linode Terraform Provider](https://www.terraform.io/docs/providers/linode/r/instance.html)' +- '[Terraform - Creating Modules](https://www.terraform.io/docs/modules/create.html)' +- '[Terraform - Module Sources](https://www.terraform.io/docs/modules/sources.html)' +--- +Terraform modules allow you to better organize your configuration code and make the code reusable. You can host your Terraform modules on remote version control services, like GitHub, for others to use. The [Terraform Module Registry](https://registry.terraform.io/) hosts community modules that you can reuse for your own Terraform configurations, or you can publish your own modules for consumption by the Terraform community. + +In this guide you will create a *Linode StackScripts* module. This module will deploy a Linode instance from a StackScript you will create. This module will include nested modules that split up the required resources between the *root module*, a `linode_instance` module, and a `stackscripts` module. + +## Before You Begin + +1. Install Terraform on your local computer using the steps found in the **Install Terraform** section of the [Use Terraform to Provision Linode Environments](https://linode.com/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/#install-terraform) guide. Your Terraform project directory should be named `linode_stackscripts`. + +2. Terraform requires an API access token. Follow the [Getting Started with the Linode API](/docs/platform/api/getting-started-with-the-linode-api-new-manager/#get-an-access-token) guide to obtain a token. + +3. Complete the steps in the **Configure Git** section of the [Getting Started with Git](/docs/development/version-control/how-to-configure-git/#configure-git) guide. + +4. Review [Deploy a WordPress Site using Terraform and StackScripts](/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/) to familiarize yourself with the Linode provider's StackScript resource. + +## Standard Module Structure + +Terraform's standard module structure provides guidance on file and directory layouts for reusable modules. If you would like to make your module public to the Terraform community, the recommended layout allows Terraform to generate documentation and index modules for the [Terraform Module Registry](https://registry.terraform.io/). + +- The primary module structure requirement is that a *root module* must exist. The root module is the directory that holds the Terraform configuration files that are applied to build your desired infrastructure. These files provide an entry point into any nested modules you might utilize. + +- Any module should include, at minimum, a `main.tf`, a `variables.tf`, and an `outputs.tf` file. This naming convention is recommended, but not enforced. + + - If using nested modules to split up your infrastructure's required resources, the `main.tf` file holds all your module blocks and any needed resources not contained within your nested modules. A simple module's `main.tf` file, without any nested modules, declares all resources within this file. + + - The `variables.tf` and `outputs.tf` files contain input variable and output variable declarations. All variables and outputs should include descriptions. + +- If using nested modules, they should be located in a root module's subdirectory named `modules/`. + +- If your modules will be hosted on Terraform's Module Registry, root modules and any nested modules should contain a `README.MD` file with a description that explains the module's intended use. + +- You can provide examples in a root module's subdirectory named `examples`. + +## Create the Linode StackScripts Module + +The Linode Stackscripts module will included two nested modules that split up the required resources between the **root module**, a `linodes` module, and a `stackscripts` module. When you are done creating all required Terraform files your directory structure will look as follows: + +{{< output >}} +linode_stackscripts/ +├── main.tf +├── outputs.tf +├── secrets.tfvars +├── terraform +├── terraform.tfvars +├── variables.tf +└── modules/ +    ├── linodes/ +    │   ├── main.tf +    │   ├── variables.tf +    │   └── outputs.tf +    └── stackscripts/ +        ├── main.tf +        ├── variables.tf +        └── outputs.tf +{{}} + +{{< note >}} +Your `linode_stackscripts` directory will likely contain other files related to the Terraform installation you completed prior to beginning the steps in this guide. +{{}} + +### Create the Linodes Module + +In this section, you will create the `linodes` module which will be in charge of creating your Linode instance. This module contains a `main.tf` file and corresponding `variables.tf` and `outputs.tf` files. + +1. If your Terraform project directory is not named `linode_stackscripts`, rename it before beginning and move into that directory: + + mv terraform linode_stackscripts + cd linode_stackscripts + +1. Create the `modules` and `linodes` subdirectories: + + mkdir -p modules/linodes + +1. Using your preferred text editor, create a `main.tf` file in `modules/linodes/` with the following resources: + + {{< file "linode_stackscripts/modules/linodes/main.tf">}} +locals { + key ="${var.key}" +} + +resource "linode_sshkey" "main_key" { + label = "${var.key_label}" + ssh_key = "${chomp(file(local.key))}" +} + +resource "linode_instance" "linode_id" { + image = "${var.image}" + label = "${var.label}" + region = "${var.region}" + type = "${var.type}" + authorized_keys = [ "${linode_sshkey.main_key.ssh_key}" ] + root_pass = "${var.root_pass}" + stackscript_id = "${var.stackscript_id}" + stackscript_data = "${var.stackscript_data}" +} +{{}} + + The `main.tf` file declares a `linode_instance` resource that deploys a Linode using a StackScript. Notice that all argument values use interpolation syntax to access variable values. You will declare the variables next and provide the variable values in the root module's `terraform.tfvars` file. Using separate files for variable declaration and assignment parameterizes your configurations and allows them to be reused as modules. + + Let’s take a closer look at each block in the `main.tf` configuration file. + + {{< file >}} +locals { + key ="${var.key}" +} + +resource "linode_sshkey" "main_key" { + label = "${var.key_label}" + ssh_key = "${chomp(file(local.key))}" +} +{{}} + + - The `locals` stanza declares a local variable `key` whose value will be provided by an input variable. + + - The `linode_sshkey` resource will create Linode SSH Keys tied to your Linode account. These keys can be reused for future Linode deployments once the resource has been created. `ssh_key = "${chomp(file(local.key))}"` uses Terraform’s built-in function `file()` to provide a local file path to the public SSH key’s location. The location of the file path is the value of the local variable `key`. The `chomp()` built-in function removes trailing new lines from the SSH key. + + {{< note >}} +If you do not already have SSH keys, follow the steps in the **Create an Authentication Key-pair** section of the [Securing Your Server Guide](/docs/security/securing-your-server/#create-an-authentication-key-pair). +{{< /note >}} + + {{< file >}} +resource "linode_instance" "linode_id" { + image = "${var.image}" + label = "${var.label}" + region = "${var.region}" + type = "${var.type}" + authorized_keys = [ "${linode_sshkey.main_key.ssh_key}" ] + root_pass = "${var.root_pass}" + stackscript_id = "${var.stackscript_id}" + stackscript_data = "${var.stackscript_data}" +} +{{}} + + The `linode_instance` resource creates a Linode instance with the listed arguments. Please note the following information: + + - The `authorized_keys` argument uses the SSH public key provided by the `linode_sshkey` resource in the previous stanza. This argument expects a value of type list, so the value must be wrapped in brackets. + + - To use an existing Linode StackScript you must use the `stackscript_id` argument and provide a valid ID as a value. Every StackScript is assigned a unique ID upon creation. Later on in the guide, you will create your own StackScript and expose its ID as an output variable in order to use its ID to deploy your Linode instance. + + - StackScripts support user defined data. This means a StackScript can use the `UDF` tag to create a variable whose value must be provided by the user of the script. This allows users to customize the behavior of a StackScript on a per-deployment basis. Any required `UDF` variable can be defined using the `stackscript_data` argument. + +1. Create the `variables.tf` file to define your resource's required variables: + + {{< file "linode_stackscripts/modules/linodes/variables.tf">}} +variable "key" { + description = "Public SSH Key's path." +} + +variable "key_label" { + description = "new SSH key label" +} + +variable "image" { + description = "Image to use for Linode instance" + default = "linode/ubuntu18.04" +} + +variable "label" { + description = "The Linode's label is for display purposes only, but must be unique." + default = "default-linode" +} + +variable "region" { + description = "The region where your Linode will be located." + default = "us-east" +} + +variable "type" { + description = "Your Linode's plan type." + default = "g6-standard-1" +} + +variable "authorized_keys" { + description = "SSH Keys to use for the Linode." + type = "list" +} + +variable "root_pass" { + description = "Your Linode's root user's password." +} + +variable "stackscript_id" { + description = "Stackscript ID." +} + +variable "stackscript_data" { + description = "Map of required StackScript UDF data." + type = "map" +} +{{}} + + - Modules must include a description for each input variable to help document your configuration’s usage. This will make it easier for anyone else to use this module. + + - Every variable can contain a default value. The default value is only used if no other value is provided. For example, if you have a favorite Linux distribution, you may want to provide it as your image variable’s default value. In this case, `linode/ubuntu18.04` is set as the default value. + + - You can declare a `type` for each variable. If no `type` is provided, the variable will default to `type = "string"`. + + - Notice that the `stackscript_data` variable is of `type = "map"`. This will allow you to provide values for as many `UDF` variables as your StackScript requires. + +1. Create the `outputs.tf` file: + + {{< file "~/linode_stackscripts/modules/linodes/outputs.tf" >}} +output "sshkey_linode" { + value = "${linode_sshkey.main_key.ssh_key}" +} +{{}} + + The `outputs.tf` file exposes any values from the resources you declared in the `main.tf` file. Any exposed values can be used by any other module within the root module. The `sshkey_linode` output variable exposes the `linode_sshkey` resource's public key. + +Now that the `linodes` module is complete, in the next section, you will create the `stackscripts` module. + +### Create the StackScripts Module + +In this section you will create the StackScripts module. This module creates a `linode_stackscripts` resource which you can use to create and modify your own Linode StackScript. + +1. Ensure you are in the `linode_stackscripts` directory and create the `stackscripts` subdirectory: + + mkdir modules/stackscripts + +1. Using your preferred text editor, create a `main.tf` file in `modules/stackscripts/` with the following resource: + + {{< file "~/linode_stackscripts/modules/stackscripts/main.tf">}} +resource "linode_stackscript" "default" { + label = "${var.stackscript_label}" + description = "${var.description}" + script = "${var.stackscript}" + images = [ "${var.stackscript_image}" ] + rev_note = "${var.rev_note}" +} +{{}} + + The `main.tf` file creates the `linode_stackscript` resource and provides the required configurations. All argument values use interpolation syntax to access input variable values. You will declare the input variables next and provide the variable values in the root module’s `terraform.tfvars` file. For more information on StackScripts see the [Automate Deployments with StackScripts](https://www.linode.com/docs/platform/stackscripts/) guide and the [Linode APIv4](https://developers.linode.com/api/v4#tag/StackScripts) documentation. + +1. Create the `variables.tf` file to define your resource's required variables: + + {{< file "~/linode_stackscripts/modules/stackscripts/variables.tf" >}} +variable "stackscript_label" { + description = "The StackScript's label is for display purposes only." +} + +variable "description" { + description = "A description for the StackScript." +} + +variable "stackscript" { + description = "The script to execute when provisioning a new Linode with this StackScript." +} +variable "stackscript_image" { + description = " A list of Image IDs representing the Images that this StackScript is compatible for deploying with." + type = "list" +} +variable "rev_note" { + description = "This field allows you to add notes for the set of revisions made to this StackScript." +} +{{}} + +1. Create the `outputs.tf` file: + + {{< file "~/linode_stackscripts/modules/stackscripts/output.tf" >}} +output "stackscript_id" { + value = "${linode_stackscript.default.id}" +} +{{}} + + The `outputs.tf` file exposes the value of the `linode_stackscript` resource's ID. Every StackScript is assigned a unique ID upon creation. You will need this ID when creating your root module. + +You have now created the StackScripts module and are ready to use both modules within the root module. You will complete this work in the next section. + +### Create the Root Module + +The root module will call the `linode` and `stackscripts` modules, satisfy their required variables and then apply those configurations to build your desired infrastructure. These configurations deploy a Linode based on a StackScript you will define in this section. When using nested modules, the modules will be hidden from your root configuration, so you'll have to re-expose any variables and outputs you require. + +1. Ensure you are in the `linode_stackscripts` directory and create the `main.tf` file: + + {{< file "linode_stackscripts/main.tf">}} +provider "linode" { + token = "${var.token}" +} + +module "stackscripts" { + source = "./modules/stackscripts" + stackscript_label = "${var.stackscript_label}" + description = "${var.description}" + stackscript = "${var.stackscript}" + stackscript_image = [ "${var.stackscript_image}" ] + rev_note = "${var.rev_note}" +} + +module "linodes" { + source = "./modules/linodes" + key = "${var.key}" + key_label = "${var.key_label}" + image = "${var.image}" + label = "${var.label}" + region = "${var.region}" + type = "${var.type}" + root_pass = "${var.root_pass}" + authorized_keys = [ "${module.linodes.sshkey_linode}" ] + stackscript_id = "${module.stackscripts.stackscript_id}" + stackscript_data = "${var.stackscript_data}" +} +{{}} + + The `main.tf` file uses the `linodes` and `stackscripts` modules that were created in the previous sections and provides the required arguments. All argument values use interpolation syntax to access variable values, which you will declare in a `variables.tf` file and then provide corresponding values for in a `terraform.tfvars` file. + + Let's review each block: + + {{< file >}} +provider "linode" { + token = "${var.token}" +} +{{}} + + The first stanza declares Linode as the provider that will manage the lifecycle of any resources declared throughout the configuration file. The Linode provider requires your Linode APIv4 token for authentication. + + {{< file >}} +module "stackscripts" { + source = "./modules/stackscripts" + stackscript_label = "${var.stackscript_label}" + description = "${var.description}" + stackscript = "${var.stackscript}" + stackscript_image = [ "${var.stackscript_image}" ] + rev_note = "${var.rev_note}" +} +{{}} + + The next stanza instructs Terraform to create an instance of the `stackscripts` module and instantiate any of the resources defined within the module. The `source` attribute provides the location of the child module's source code and is required whenever you create an instance of a module. All other attributes are determined by the module. Notice that all the attributes included in the module block correspond to the `linode_stackscript` resource's arguments declared in the `main.tf` file of the `stackscripts` module. + + {{< file >}} +module "linodes" { + source = "./modules/linodes" + key = "${var.key}" + key_label = "${var.key_label}" + image = "${var.image}" + label = "${var.label}" + group = "${var.group}" + region = "${var.region}" + type = "${var.type}" + root_pass = "${var.root_pass}" + authorized_keys = [ "${module.linodes.sshkey_linode}" ] + stackscript_id = "${module.stackscripts.stackscript_id}" + stackscript_data = "${var.stackscript_data}" +} +{{}} + + This stanza creates an instance of the `linodes` module and then instantiates the resources you defined in the module. Notice that `authorized_keys = [ "${module.linodes.sshkey_id}" ]` and `stackscript_id = "${module.stackscripts.stackscript_id}"` both access values exposed as output variables by the `linodes` and `stackscripts` modules. Any module's exposed output variables can be referenced in your root module's `main.tf` file. + +1. Create the `variables.tf` file to declare the input variables required by the module instances: + + {{< file "~/linode_stackscripts/variables.tf">}} +variable "token" { + description = " Linode API token" +} + +variable "stackscript_label" { + description = "The StackScript's label is for display purposes only." +} + +variable "description" { + description = "A description for the StackScript." +} + +variable "stackscript" { + description = "The script to execute when provisioning a new Linode with this StackScript." +} + +variable "stackscript_image" { + description = "A list of Image IDs representing the Images that this StackScript is compatible for deploying with." +} + +variable "rev_note" { + description = "This field allows you to add notes for the set of revisions made to this StackScript." +} + +variable "key" { + description = "Public SSH Key's path." +} + +variable "key_label" { + description = "New SSH key label." +} + +variable "image" { + description = "Image to use for Linode instance." + default = "linode/ubuntu18.04" +} + +variable "label" { + description = "The Linode's label is for display purposes only, but must be unique." + default = "default-linode" +} + +variable "region" { + description = "The region where your Linode will be located." + default = "us-east" +} + +variable "type" { + description = "Your Linode's plan type." + default = "g6-standard-1" +} + +variable "root_pass" { + description = "Your Linode's root user's password." +} + +variable "stackscript_data" { + description = "Map of required StackScript UDF data." + type = "map" +} +{{}} + +1. Create the `outputs.tf` file: + + {{< file "~/linode_stackscripts/outputs.tf" >}} +output "stackscript_id" { + value = "${module.stackscripts.stackscript_id}" +} +{{}} + + In the `outputs.tf` file you will re-expose the output variables exposed by the `stackscripts` module. + +1. Create the `terraform.tfvars` file to provide values for all input variables defined in the `variables.tf` file. This file will exclude any values that provide sensitive data, like passwords and API tokens. A file containing sensitive values will be created in the next step: + + {{< file "~/linode_stackscripts/terraform.tfvars " >}} +key = "~/.ssh/id_rsa.pub" +key_label = "my-ssh-key" +label = "my-linode" +stackscript_data { + my_username = "username" + my_hostname = "linode-hostname" +} +stackscript_id = "base-ubuntu-deployment" +stackscript_label = "base-ubuntu-deployment" +description = "A base deployment for Ubuntu 18.04 that creates a limited user account." +stackscript = < +# +# +# + +source + +set -x + +MY_IP=system_primary_ip +system_set_hostname "$MY_HOSTNAME" +system_add_host_entry "$MY_IP" "$MY_HOSTNAME" +user_add_sudo "$MY_USERNAME" "$MY_PASSWORD" +user_add_pubkey "$MY_USERNAME" "$MY_USERPUBKEY" +ssh_disable_root +goodstuff +EOF +stackscript_image = "linode/ubuntu18.04" +rev_note = "First revision of my StackScript created with the Linode Terraform provider." +{{}} + + The `terraform.tfvars` file supplies all values required by the `linodes` and `stackscripts` modules. Ensure you replace any values with your own values when using this example file. + + The `stackscript` variable provides the actual contents of the StackScript you create. This example StackScript requires four `UDF` values: `my_hostname`, `my_username`, `my_password`, and `my_userpubkey`. The `my_hostname` and `my_username` values are supplied by the `stackscript_data` map. The `my_password` and `my_userpubkey` values will be provided in the next step. + + The StackScript will then use these values to create a limited user account; set a hostname; add a host entry; add the created user to the `sudo` group; disable SSH access for the root user; and install vim, wget, and less. This StackScript uses bash functions defined in the Linode Community [StackScript Bash Library](https://www.linode.com/stackscripts/view/1). + +1. Create a file named `secrets.tfvars` to hold any sensitive values: + + {{< file "~/linode_stackscripts/secrets.tfvars">}} +token = "my-linode-api-token" +root_pass = "my-secure-root-password" +stackscript_data { + my_password = "my-limited-users-password" + my_userpubkey = "my-public-ssh-key" +} +{{}} + + This file contains all sensitive data needed for your Linode deployment. Ensure you replace all values with your own secure passwords and your Linode account's APIv4 token. This file should never be tracked in version control software and should be listed in your `.gitignore` file if using [GitHub](https://github.com/). + + {{< note >}} + There are several other options available for secrets management with Terraform. For more information on this subject, see [Secrets Management with Terraform](/docs/applications/configuration-management/secrets-management-with-terraform). + {{}} + +You are now ready to apply your `linode_stackscripts` module's Terraform configuration. These steps will be completed in the next section. + +## Initialize, Plan and Apply the Terraform Configuration + +Whenever a new provider is used in a Terraform configuration, it must first be initialized. The initialization process downloads and installs the provider’s plugin and performs any other steps needed for its use. Before applying your configuration, it is also useful to view your configuration’s execution plan before making any actual changes to your infrastructure. In this section, you will complete all these steps. + +1. Initialize the Linode provider. Ensure you are in the `linode_stackscripts` directory before running this command: + + terraform init + + You will see a message that confirms that the provider plugins have been successfully initialized. + +1. Run the Terraform plan command: + + terraform plan -var-file="secrets.tfvars" -var-file="terraform.tfvars" + + Terraform plan won’t take any action or make any changes on your Linode account. Instead, an analysis is done to determine which actions (i.e. Linode instance creations, deletions, or modifications) are required to achieve the state described in your configuration. + +1. You are now ready to create the infrastructure defined in your root module's `main.tf` configuration file: + + terraform apply -var-file="secrets.tfvars" -var-file="terraform.tfvars" + + Since you are using multiple variable value files, you must call each file individually using the `var-file` argument. You will be prompted to confirm the `apply` action. Type *yes* and hit **enter**. Terraform will begin to create the resources you’ve defined throughout this guide. This process will take a couple of minutes to complete. Once the infrastructure has been successfully built you will see a similar output: + + {{< output >}} + Apply complete! Resources: 3 added, 0 changed, 0 destroyed. + {{}} + +1. To verify the deployment, retrieve your Linode instance's IP address: + + terraform show | grep 'ip_address' + + You should see a similar output: + + {{< output >}} + ip_address = 192.0.2.0 + {{}} + +1. Open a new shell session and SSH into your Linode using the IP address you retrieved in the previous step and the username you defined in the `terraform.tfvars` file's `my_username` variable: + + ssh username@192.0.2.0 + + You should be able to access your Linode and then verify that what you defined in the StackScript was executed. + +## Version Control Your Terraform Module + +To make the `linode_stackscripts` module available to other team members, you can version control it using [GitHub](https://github.com/). Before completing the steps in this section, ensure you have completed the steps in the **Configure Git** section of the [Getting Started with Git](/docs/development/version-control/how-to-configure-git/#configure-git) guide. + +1. In the `linode_stackscripts` directory create a `.gitignore` file: + + {{< file "~/linode_stackscripts/.gitignore" >}} +secrets.tfvars +.terraform/ +terraform/ +terraform.tfstate +{{}} + + {{< note >}} +If there are any files related to the Terraform installation steps completed before beginning this guide (i.e zip files and checksum files), you can remove these files from the `linode_stackscripts` directory, since you should not track them in version control and they are no longer necessary. +{{}} + +1. Initialize the git repository: + + git init + + Stage all the files you’ve created so far for your first commit: + + git add -A + +1. Commit all the `linode_stackscripts` files: + + git commit -m "Initial commit" + +1. Navigate to your GitHub account and [create a new repository](https://help.github.com/articles/creating-a-new-repository/). Ensure you name the repository the same name as that of your Terraform module. In this example, the GitHub repository will be named `linode_stackscripts`. + +1. At the top of your GitHub repository's **Quick Setup** page, copy the remote repository URL. + +1. Return to your local computer's `linode_stackscripts` directory and add the URL for the remote repository: + + git remote add origin https://github.com/my-github/linode_stackscripts.git + +1. Push your local `linode_stackscripts` repository to your remote GitHub repository: + + git push -u origin master + +Your Terraform module is now tracked via GitHub and can be used, shared and modified by anyone who has access to your GitHub account. + +### Invoking Your GitHub-Hosted Module + +In the future, you can source this module from GitHub within your Terraform module declarations. You would write your module block like the following: + +{{< file >}} +module "linode_stackscripts" { + source = "github.com/username/linode_stackscripts" + + VARIABLES HERE + . . . +} +{{< /file >}} \ No newline at end of file diff --git a/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/index.md b/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/index.md new file mode 100644 index 00000000000..14f6ab7bf05 --- /dev/null +++ b/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/index.md @@ -0,0 +1,364 @@ +--- +author: + name: Linode Community + email: docs@linode.com +description: 'In this guide you will learn how to use a Community StackScript to deploy WordPress on a Linode using Terraform.' +keywords: ['terraform','stackscripts','wordpress','orchestration'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-12 +modified: 2018-12-12 +modified_by: + name: Linode +title: "Deploy a WordPress Site Using Terraform and Linode StackScripts" +contributor: + name: Linode +external_resources: +- '[Terraform Linode Provider](https://www.terraform.io/docs/providers/linode/index.html)' +- '[Terraform Input Variables](https://www.terraform.io/intro/getting-started/variables.html)' +--- + +Linode's Terraform provider supports [StackScripts](/docs/platform/stackscripts/). StackScripts allow you to automate the deployment of custom software on top of Linode's default Linux images, or on any of your [saved custom images](/docs/platform/disk-images/linode-images/). You can create your own StackScripts, use a StackScript created by Linode, or use a Community StackScript. + +In this guide you will learn how to use a Community StackScript to deploy WordPress on a Linode using Terraform. + +{{< caution >}} +Following this guide will result in the creation of [billable Linode resources](/docs/platform/billing-and-support/billing-and-payments/#how-hourly-billing-works) on your account. To prevent continued billing for these resources, [remove them](#optional-destroy-the-linode-resources) from your account when you have completed the guide, if desired. +{{< /caution >}} + +## Before You Begin + +1. Install Terraform on your computer by following the *Install Terraform* section of our [Use Terraform to Provision Linode Environments](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/#install-terraform) guide. + +1. Terraform requires an API access token. Follow the [Getting Started with the Linode API](/docs/platform/api/getting-started-with-the-linode-api-new-manager/#get-an-access-token) guide to obtain one. + +1. If you have not already, [assign Linode's name servers](/docs/platform/manager/dns-manager/#use-linode-s-name-servers-with-your-domain) to your domain at your domain name's registrar. + +1. Browse the existing [StackScripts Library](https://www.linode.com/stackscripts/) to familiarize yourself with common tasks you can complete with existing StackScripts. + +## Create a Terraform Configuration + +Terraform defines the elements of your Linode infrastructure inside of configuration files. Terraform refers to these infrastructure elements as *resources*. Once you declare your Terraform configuration, you then *apply* it, which results in the creation of those resources on the Linode platform. + +### Create the Terraform Configuration File + +1. Ensure that you are in the `terraform` directory. + + cd ~/terraform + +1. Using your preferred text editor, create a Terraform configuration file named `main.tf` to hold your resource definitions: + + {{< file "~/terraform/main.tf">}} +provider "linode" { + token = "${var.token}" +} + +resource "linode_sshkey" "my_wordpress_linode_ssh_key" { + label = "my_ssh_key" + ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}" +} + +resource "random_string" "my_wordpress_linode_root_password" { + length = 32 + special = true +} + +resource "linode_instance" "my_wordpress_linode" { + image = "${var.image}" + label = "${var.label}" + region = "${var.region}" + type = "${var.type}" + authorized_keys = [ "${linode_sshkey.my_wordpress_linode_ssh_key.ssh_key}" ] + root_pass = "${random_string.my_wordpress_linode_root_password.result}" + stackscript_id = "${var.stackscript_id}" + stackscript_data = "${var.stackscript_data}" +} + +resource "linode_domain" "my_wordpress_domain" { + domain = "${var.domain}" + soa_email = "${var.soa_email}" + type = "master" + } + +resource "linode_domain_record" "my_wordpress_domain_www_record" { + domain_id = "${linode_domain.my_wordpress_domain.id}" + name = "www" + record_type = "${var.a_record}" + target = "${linode_instance.my_wordpress_linode.ipv4[0]}" +} + +resource "linode_domain_record" "my_wordpress_domain_apex_record" { + domain_id = "${linode_domain.my_wordpress_domain.id}" + name = "" + record_type = "${var.a_record}" + target = "${linode_instance.my_wordpress_linode.ipv4[0]}" +} +{{}} + + The Terraform configuration file uses an [interpolation syntax](https://www.terraform.io/docs/configuration/interpolation.html) to reference Terraform [*input variables*](https://learn.hashicorp.com/terraform/getting-started/variables.html), call Terraform's [built-in functions](https://www.terraform.io/docs/configuration/interpolation.html#built-in-functions), and reference attributes of other resources. + + Variables and their values will be created in separate files later on in this guide. Using separate files for variable declaration allows you to avoid hard-coding values into your resources. This strategy can help you reuse, share, and version control your Terraform configurations. + +### Examining the Terraform Configuration + +Let's take a closer look at each block in the configuration file: + +1. The first stanza declares Linode as the [Terraform provider](https://www.terraform.io/docs/providers/) that will manage the life cycle of any resources declared throughout the configuration file. The Linode provider requires your Linode APIv4 token for authentication: + + {{< file >}} +provider "linode" { + token = "${var.token}" +} +{{}} + +1. The next resource configures an SSH Key that will be uploaded to your Linode instance later in the configuration file: + + {{< file >}} +resource "linode_sshkey" "my_wordpress_linode_ssh_key" { + label = "my_ssh_key" + ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}" +} +{{}} + + `ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}"` uses Terraform's built-in `file()` function to provide a local file path to the public SSH key's location. The `chomp()` built-in function removes trailing new lines from the SSH key. + + {{< note >}} +If you do not already have SSH keys, follow the steps in the *Create an Authentication Key-pair* section of the [Securing Your Server Guide](/docs/security/securing-your-server/#create-an-authentication-key-pair). +{{< /note >}} + +1. The `random_string` resource can be used to create a random string of 32 characters. The `linode_instance` resource will use it to create a root user password: + + {{< file >}} +resource "random_string" "my_wordpress_linode_root_password" { + length = 32 + special = true +} +{{}} + +1. The `linode_instance` resource creates a Linode with the declared configurations: + + {{< file >}} +resource "linode_instance" "my_wordpress_linode" { + image = "${var.image}" + label = "${var.label}" + region = "${var.region}" + type = "${var.type}" + authorized_keys = [ "${linode_sshkey.my_wordpress_linode_ssh_key.ssh_key}" ] + root_pass = "${random_string.my_wordpress_linode_root_password.result}" + stackscript_id = "${var.stackscript_id}" + stackscript_data = "${var.stackscript_data}" +} +{{}} + + - The `authorized_keys` argument uses the SSH public key provided by the `linode_sshkey` resource in the previous stanza. This argument expects a value of type `list`, so the value must be wrapped in brackets. + + - The `root_pass` argument is assigned to the value of the `random_string` resource previously declared. + + - To use an existing StackScript you must use the `stackscript_id` argument and provide a valid ID as a value. Every StackScript is assigned a unique ID upon creation. This guide uses the [WordPress on Ubuntu 16.04](https://www.linode.com/stackscripts/view/81736) StackScript provided by Linode user [hmorris](https://www.linode.com/stackscripts/profile/hmorris). This StackScript's ID will be assigned to a Terraform variable later in this guide. + + StackScripts support user defined data. A StackScript can use the [`UDF` tag](/docs/platform/stackscripts/#variables-and-udfs) to create a variable whose value must be provided by the user of the script. This allows users to customize the behavior of a StackScript on a per-deployment basis. Any required `UDF` variable can be defined using the `stackscript_data` argument. + + The StackScript will be responsible for installing WordPress on your Linode, along with all other requirements, like installing and configuring the Apache Web Server, configuring the Virtual Hosts file, and installing MySQL. + + - Other arguments are given values by the Terraform variables that will be declared later in this guide. + +1. In order to complete your WordPress site's configuration, you need to create a domain and corresponding domain records for your site. The `linode_domain` and `linode_domain_record` resources handle these configurations: + + {{< file >}} +resource "linode_domain" "my_wordpress_domain" { + domain = "${var.domain}" + soa_email = "${var.soa_email}" + type = "master" + } + +resource "linode_domain_record" "my_wordpress_domain_www_record" { + domain_id = "${linode_domain.my_wordpress_domain.id}" + name = "www" + record_type = "${var.a_record}" + target = "${linode_instance.linode_id.ipv4[0]}" +} + +resource "linode_domain_record" "my_wordpress_domain_apex_record" { + domain_id = "${linode_domain.my_wordpress_domain.id}" + name = "" + record_type = "${var.a_record}" + target = "${linode_instance.my_wordpress_linode.ipv4[0]}" +} +{{}} + + {{< note >}} +If you are not familiar with the Domain Name System (DNS), review the [DNS Records: An Introduction](/docs/networking/dns/dns-records-an-introduction/) guide. +{{< /note >}} + + The `linode_domain` resource creates a [domain zone](/docs/platform/manager/dns-manager/#domain-zones) for your domain. + + Each `linode_domain_record` resource retrieves the `linode_domain` resource's ID and assigns it to that record's `domain_id` argument. Each record's `target` argument retrieves the IP address from the Linode instance. Every `linode_instance` resource exposes [several attributes](https://www.terraform.io/docs/providers/linode/r/instance.html#attributes), including a Linode's IPv4 address. + +### Define the Input Variables + +In the `terraform` directory, create a file named `variables.tf`. This will define all the variables that were used in the `main.tf` file in the previous section. The values for these variables (aside from their default values) will be assigned in another file: + +{{< file "~/terraform/variables.tf" >}} +variable "token" { + description = "Linode API Personal Access Token" +} + +variable "image" { + description = "Image to use for Linode instance" + default = "linode/ubuntu16.04lts" +} + +variable "label" { + description = "The Linode's label is for display purposes only." + default = "default-linode" +} + +variable "region" { + description = "The region where your Linode will be located." + default = "us-east" +} + +variable "type" { + description = "Your Linode's plan type." + default = "g6-standard-1" +} + +variable "stackscript_id" { + description = "Stackscript ID" +} + +variable "stackscript_data" { + description = "Map of required StackScript UDF data." + type = "map" +} + +variable "domain" { + description = "The domain this domain represents." +} + +variable "soa_email" { + description = "Start of Authority email address. This is required for master domains." +} + +variable "a_record" { + description = "The type of DNS record. For example, `A` records associate a domain name with an IPv4 address." + default = "A" +} + {{}} + +{{< note >}} +It is recommended to include a `description` attribute for each input variable to help document your configuration's usage. This will make it easier for anyone else to use this Terraform configuration. +{{< /note >}} + +Every variable can contain a `default` value. The `default` value is only used if no other value is provided. You can also declare a `type` for each variable. If no type is provided, the variable will default to `type = "string"`. + +The `stackscript_data` variable is of type `map`. This will allow you to provide values for as many `UDF` variables as your StackScript requires. + +### Assign Values to the Input Variables + +Terraform allows you to assign variables in many ways. For example, you can assign a variable value via the command line when running `terraform apply`. In order to persist variable values, you can also create files to hold all your values. + +{{< note >}} +There are several other options available for secrets management with Terraform. For more information on this, see [Secrets Management with Terraform](/docs/applications/configuration-management/secrets-management-with-terraform/). +{{}} + +Terraform will automatically load any file named `terraform.tfvars` and use its contents to populate variables. However, you should separate out any sensitive values, like passwords and tokens, into their own file. Keep this sensitive file out of version control. + +1. Create a file named `terraform.tfvars` in your `terraform` directory to hold all non-sensitive values: + + {{< file "~/terraform/terraform.tfvars">}} +label = "wp-linode" +stackscript_id = "81736" +stackscript_data = { + ssuser = "username" + hostname = "wordpress" + website = "example.com" + dbuser = "wpuser" +} +domain = "example.com" +soa_email = "user@email.com" +{{}} + +1. Create a file name `secrets.tfvars` in your `terraform` directory to hold any sensitive values: + + {{< file "~/terraform/secrets.tfvars">}} +token = "my-linode-api4-token" +stackscript_data = { + sspassword = "my-secure-password" + db_password = "another-secure-password" + dbuser_password = "a-third-secure-password" +} +{{}} + + {{< note >}} +It is helpful to reference Terraform's [Linode provider](https://www.terraform.io/docs/providers/linode/) documentation and the [Linode APIv4 documentation](https://developers.linode.com/api/v4) for assistance in determining appropriate values for Linode resources. +{{< /note >}} + +1. Replace the following values in your new `.tfvars` files: + + - `token` should be replaced with your own Linode account's APIv4 token. + + - For security purposes, the StackScript will create a limited Linux user on your Linode. `ssuser` should be replaced with your desired username for this user. + + - `sspassword`, `db_password`, and `dbuser_password` should be replaced with secure passwords of your own. + + - `domain` should be replaced with your WordPress site's domain address. + + - `soa_email` should be the email address you would like to use for your [Start of Authority](/docs/networking/dns/dns-records-an-introduction/#soa) email address. + +## Initialize, Plan, and Apply the Terraform Configuration + +Your Terraform configuration has been recorded, but you have not told Terraform to create the resources yet. To do this, you will invoke commands from Terraform's CLI. + +### Initialize + +Whenever a new provider is used in a Terraform configuration, it must be initialized before you can create resources with it. The initialization process downloads and installs the provider's plugin and performs any other steps needed to prepare for its use. + +Navigate to your `terraform` directory in your terminal and run: + + terraform init + +You will see a message that confirms that the Linode provider plugins have been successfully initialized. + +### Plan + +It can be useful to view your configuration's execution plan before actually committing those changes to your infrastructure. Terraform includes a `plan` command for this purpose. Run this command from the `terraform` directory: + + terraform plan \ + -var-file="secrets.tfvars" \ + -var-file="terraform.tfvars" + +`plan` won’t take any actions or make any changes on your Linode account. Instead, an analysis is done to determine which actions (i.e. Linode resource creations, deletions, or modifications) are required to achieve the state described in your configuration. + +### Apply + +You are now ready to create the infrastructure defined in your `main.tf` configuration file: + +1. Run Terraform's `apply` command from the `terraform` directory: + + terraform apply \ + -var-file="secrets.tfvars" \ + -var-file="terraform.tfvars" + + Since you are using multiple variable value files, you must include each file individually using the `var-file` argument. You will be prompted to confirm the `apply` action. Type *yes* and press **enter**. + +2. Terraform will begin to create the resources you've defined throughout this guide. This process will take several minutes to complete. Once the infrastructure has been successfully built you will see a similar output: + + {{< output >}} +Apply complete! Resources: 6 added, 0 changed, 0 destroyed. +{{< /output >}} + +3. Navigate to your WordPress site's domain and verify that the site loads. You may have to wait a few minutes more after the `terraform apply` command returns, as the StackScript takes time to install WordPress. Additionally, it make take some time for your domain name changes to propagate: + + ![Install WordPress](wp-install.png) + +4. Complete the remaining WordPress configuration steps provided by the prompts. + +## (Optional) Destroy the Linode Resources + +If you do not want to keep using the resources created by Terraform in this guide, run the `destroy` command from the `terraform` directory: + + terraform destroy \ + -var-file="secrets.tfvars" \ + -var-file="terraform.tfvars" + +Terraform will prompt you to confirm this action. Enter *yes* to proceed. \ No newline at end of file diff --git a/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/wp-install.png b/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/wp-install.png new file mode 100644 index 00000000000..f30bfb902a0 Binary files /dev/null and b/docs/applications/configuration-management/deploy-a-wordpress-site-using-terraform-and-linode-stackscripts/wp-install.png differ diff --git a/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/index.md b/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/index.md new file mode 100644 index 00000000000..b780ea9b60b --- /dev/null +++ b/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/index.md @@ -0,0 +1,731 @@ +--- +author: + name: Linode + email: docs@linode.com +description: 'This guide will describe how to import existing Linode infrastructure into Terraform using the official Linode provider plugin.' +keywords: ['terraform','configuration management','import'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-17 +modified: 2018-12-17 +modified_by: + name: Linode +title: "Import Existing Infrastructure to Terraform" +contributor: + name: Linode +external_resources: +- '[Terraform Import Usage](https://www.terraform.io/docs/import/usage.html)' +- '[Terraform Linode Instance Documentation](https://www.terraform.io/docs/providers/linode/r/instance.html)' +--- + +Terraform is an orchestration tool that uses declarative code to build, change, and version infrastructure that is made up of server instances and services. You can use [Linode's official Terraform provider](https://www.terraform.io/docs/providers/linode/index.html) to interact with Linode services. Existing Linode infrastructure can be imported and brought under Terraform management. This guide will describe how to import existing Linode infrastructure into Terraform using the official Linode provider plugin. + +## Before You Begin + +1. Terraform and the Linode Terraform provider should be installed in your development environment. You should also have a basic understanding of [Terraform resources](https://www.terraform.io/docs/configuration/resources.html). To install and learn about Terraform, read our [Use Terraform to Provision Linode Environments](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/) guide. + +2. To use Terraform you must have a valid API access token. For more information on creating a Linode API access token, visit our [Getting Started with the Linode API](/docs/platform/api/getting-started-with-the-linode-api/#get-an-access-token) guide. + +3. This guide uses the Linode CLI to retrieve information about the Linode infrastructure you will import to Terraform. For more information on the setup, installation, and usage of the Linode CLI, check out the [Using the Linode CLI](https://www.linode.com/docs/platform/api/using-the-linode-cli/) guide. + +## Terraform's Import Command + +Throughout this guide the `terraform import` command will be used to import Linode resources. At the time of writing this guide, the import command **does not generate a Terraform resource configuration**. Instead, it imports your existing resources into Terraform's *state*. + +State is Terraform's stored JSON mapping of your current Linode resources to their configurations. You can access and use the information provided by the state to manually create a corresponding resource configuration file and manage your existing Linode infrastructure with Terraform. + +Additionally, there is no current way to import more than one resource at a time. **All resources must be individually imported**. + +{{< caution >}} +When importing your infrastructure to Terraform, failure to accurately provide your Linode service's ID information can result in the unwanted alteration or destruction of the service. Please follow the instructions provided in this guide carefully. It might be beneficial to use multiple [Terraform Workspaces](https://www.terraform.io/docs/state/workspaces.html) to manage separate testing and production infrastructures. +{{< /caution >}} + +## Import a Linode to Terraform + +### Retrieve Your Linode's ID + +1. Using the Linode CLI, retrieve a list of all your Linode instances and find the ID of the Linode you would like to manage under Terraform: + + linode-cli linodes list --json --pretty + + {{< output >}} +[ +  { +    "id": 11426126, +    "image": "linode/debian9", +    "ipv4": [ +    "192.0.2.2" +    ], +    "label": "terraform-import", +    "region": "us-east", +    "status": "running", +    "type": "g6-standard-1" +  } +] +{{< /output >}} + + This command will return a list of your existing Linodes in JSON format. From the list, find the Linode you would like to import and copy down its corresponding `id`. In this example, the Linode's ID is `11426126`. You will use your Linode's ID to import your Linode to Terraform. + +### Create An Empty Resource Configuration + +1. Ensure you are in your [Terraform project directory](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/#install-terraform). Create a Terraform configuration file to manage the Linode instance you will import in the next section. Your file can be named anything you like, but it must end in `.tf`. Add a Linode provider block with your API access token and an empty `linode_instance` resource configuration block in the file: + + {{< note >}} +The example resource block defines `example_label` as the label. This can be changed to any value you prefer. This label is used to reference your Linode resource configuration within Terraform, and does not have to be the same label originally assigned to the Linode when it was created outside of Terraform. +{{}} + + {{< file "linode_import.tf" >}} +provider "linode" { + token = "your_API_access_token" +} + +resource "linode_instance" "example_label" {} +{{< /file >}} + +### Import Your Linode to Terraform + +1. Run the `import` command, supplying the `linode_instance` resource's label, and the Linode's ID that was retrieved in the [Retrieve Your Linode's ID](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#retrieve-your-linode-s-id) section : + + terraform import linode_instance.example_label linodeID + + You should see a similar output: + + {{< output >}} +linode_instance.example_label: Importing from ID "11426126"... +linode_instance.example_label: Import complete! + Imported linode_instance (ID: 11426126) +linode_instance.example_label: Refreshing state... (ID: 11426126) + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +{{< /output >}} + + This command will create a `terraform.tfstate` file with information about your Linode. You will use this information to fill out your resource configuration. + +1. To view the information created by `terraform import`, run the `show` command. This command will display a list of key-value pairs representing information about the imported Linode instance. + + terraform show + + You should see an output similar to the following: + + {{< output >}} +linode_instance.example_label: + id = 11426126 + alerts.# = 1 + alerts.0.cpu = 90 + alerts.0.io = 10000 + alerts.0.network_in = 10 + alerts.0.network_out = 10 + alerts.0.transfer_quota = 80 + backups.# = 1 + boot_config_label = My Debian 9 Disk Profile + config.# = 1 + config.0.comments = + config.0.devices.# = 1 + config.0.devices.0.sda.# = 1 + config.0.devices.0.sda.0.disk_id = 24170011 + config.0.devices.0.sda.0.disk_label = Debian 9 Disk + config.0.devices.0.sda.0.volume_id = 0 + config.0.devices.0.sdb.# = 1 + config.0.devices.0.sdb.0.disk_id = 24170012 + config.0.devices.0.sdb.0.disk_label = 512 MB Swap Image + config.0.devices.0.sdb.0.volume_id = 0 + config.0.devices.0.sdc.# = 0 + config.0.devices.0.sdd.# = 0 + config.0.devices.0.sde.# = 0 + config.0.devices.0.sdf.# = 0 + config.0.devices.0.sdg.# = 0 + config.0.devices.0.sdh.# = 0 + config.0.helpers.# = 1 + config.0.helpers.0.devtmpfs_automount = true + config.0.helpers.0.distro = true + config.0.helpers.0.modules_dep = true + config.0.helpers.0.network = true + config.0.helpers.0.updatedb_disabled = true + config.0.kernel = linode/grub2 + config.0.label = My Debian 9 Disk Profile + config.0.memory_limit = 0 + config.0.root_device = /dev/root + config.0.run_level = default + config.0.virt_mode = paravirt + disk.# = 2 + disk.0.authorized_keys.# = 0 + disk.0.filesystem = ext4 + disk.0.id = 24170011 + disk.0.image = + disk.0.label = Debian 9 Disk + disk.0.read_only = false + disk.0.root_pass = + disk.0.size = 50688 + disk.0.stackscript_data.% = 0 + disk.0.stackscript_id = 0 + disk.1.authorized_keys.# = 0 + disk.1.filesystem = swap + disk.1.id = 24170012 + disk.1.image = + disk.1.label = 512 MB Swap Image + disk.1.read_only = false + disk.1.root_pass = + disk.1.size = 512 + disk.1.stackscript_data.% = 0 + disk.1.stackscript_id = 0 + group = Terraform + ip_address = 192.0.2.2 + ipv4.# = 1 + ipv4.1835604989 = 192.0.2.2 + ipv6 = 2600:3c03::f03c:91ff:fef6:3ebe/64 + label = terraform-import + private_ip = false + region = us-east + specs.# = 1 + specs.0.disk = 51200 + specs.0.memory = 2048 + specs.0.transfer = 2000 + specs.0.vcpus = 1 + status = running + swap_size = 512 + type = g6-standard-1 + watchdog_enabled = true +{{< /output >}} + + You will use this information in the next section. + + {{< note >}} +There is a current bug in the Linode Terraform provider that causes the Linode's `root_device` configuration to display an import value of `/dev/root`, instead of `/dev/sda`. This is visible in the example output above: `config.0.root_device = /dev/root`. However, the correct disk, `/dev/sda`, is in fact targeted. For this reason, when running the `terraform plan` or the `terraform apply` commands, the output will display `config.0.root_device: "/dev/root" => "/dev/sda"`. + +You can follow the corresponding [GitHub issue](https://github.com/terraform-providers/terraform-provider-linode/issues/10) for more details. +{{< /note >}} + +### Fill In Your Linode's Configuration Data + +As mentioned in the [Terraform's Import Command](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#terraform-s-import-command) section, you must manually create your resource configurations when importing existing infrastructure. + + 1. Fill in the configuration values for the `linode_instance` resource block. In the example below, the necessary values were collected from the output of the `terraform show` command applied in Step 2 of the [Import Your Linode to Terraform](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#import-your-linode-to-terraform) section. The file's comments indicate the corresponding keys used to determine the values for the `linode_instance` configuration block. + + {{< file "linode_instance_import.tf" >}} +provider "linode" { + token = "a12b3c4e..." +} + +resource "linode_instance" "example_label" { + label = "terraform-import" #label + region = "us-east" #region + type = "g6-standard-1" #type + config { + label = "My Debian 9 Disk Profile" #config.0.label + kernel = "linode/grub2" #config.0.kernel + root_device = "/dev/sda" #config.0.root_device + devices { + sda = { + disk_label = "Debian 9 Disk" #config.0.devices.0.sda.0.disk_label + } + sdb = { + disk_label = "512 MB Swap Image" #config.0.devices.0.sdb.0.disk_label + } + } + } + disk { + label = "Debian 9 Disk" #disk.0.label + size = "50688" #disk.0.size + } + disk { + label = "512 MB Swap Image" #disk.1.label + size = "512" #disk.1.size + } +} + {{< /file >}} + + {{< note >}} +If your Linode uses more than two disks (for instance, if you have attached a [Block Storage Volume](/docs/platform/block-storage/how-to-use-block-storage-with-your-linode-new-manager/)), you will need to add those disks to your Linode resource configuration block. In order to add a disk, you must add the disk to the `devices` stanza and create an additional `disk` stanza. +{{< /note >}} + + {{< note >}} +If you have more than one [configuration profile](/docs/platform/disk-images/disk-images-and-configuration-profiles/), you must choose which profile to boot from with the `boot_config_label` argument. For example: + + resource "linode_instance" "example_label" { + boot_config_label = "My Debian 9 Disk Profile" + ... +{{< /note >}} + +1. To check for errors in your configuration, run the `plan` command: + + terraform plan + + `terraform plan` shows you the changes that would take place if you were to apply the configurations with a `terraform apply`. Running `terraform plan` is a good way to determine if the configuration you provided is exact enough for Terraform to take over the management of your Linode. + + {{< note >}} + Running `terraform plan` will display any changes that will be applied to your existing infrastructure based on your configuration file(s). However, you will **not be notified** about the **addition and removal of disks** with `terraform plan`. For this reason, it is vital that the values you include in your `linode_instance` resource configuration block match the values generated from running the `terraform show` command. + {{}} + +1. Once you have verified the configurations you provided in the `linode_instance` resource block, you are ready to begin managing your Linode instance with Terraform. Any changes or updates can be made by updating your `linode_instance_import.tf` file, then verifying the changes with the `terrform plan` command, and then finally applying the changes with the `terraform apply` command. + + For more available configuration options, visit the [Linode Instance](https://www.terraform.io/docs/providers/linode/r/instance.html) Terraform documentation. + +## Import a Domain to Terraform + +### Retrieve Your Domain's ID + +1. Using the Linode CLI, retrieve a list of all your domains to find the ID of the domain you would like to manage under Terraform: + + linode-cli domains list --json --pretty + + You should see output like the following: + + {{< output >}} +[ +  { +    "domain": "import-example.com", +    "id": 1157521, +    "soa_email": "webmaster@import-example.com", +    "status": "active", +    "type": "master" +  } +] +{{< /output >}} + + Find the domain you would like to import and copy down the ID. You will need this ID to import your domain to Terraform. + +### Create an Empty Resource Configuration + +1. Ensure you are in your [Terraform project directory](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/#install-terraform). Create a Terraform configuration file to manage the domain you will import in the next section. Your file can be named anything you like, but must end in `.tf`. Add a Linode provider block with your API access token and an empty `linode_domain` resource configuration block to the file: + + {{< file "domain_import.tf" >}} +provider "linode" { + token = "Your API Token" +} + +resource "linode_domain" "example_label" {} +{{< /file >}} + +### Import Your Domain to Terraform + +1. Run the `import` command, supplying the `linode_domain` resource's label, and the domain ID that was retrieved in the [Retrieve Your Domain's ID](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#retrieve-your-domain-s-id) section: + + terraform import linode_domain.example_label domainID + + You should see output similar to the following: + + {{< output >}} +linode_domain.example_label: Importing from ID "1157521"... +linode_domain.example_label: Import complete! + Imported linode_domain (ID: 1157521) +linode_domain.example_label: Refreshing state... (ID: 1157521) + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +{{< /output >}} + + This command will create a `terraform.tfstate` file with information about your domain. You will use this information to fill out your resource configuration. + +1. To view the information created by `terraform import`, run the show command. This command will display a list of key-value pairs representing information about the imported domain: + + terraform show + + You should see output like the following: + + {{< output >}} +linode_domain.example_label: + id = 1157521 + description = + domain = import-example.com + expire_sec = 0 + group = + master_ips.# = 0 + refresh_sec = 0 + retry_sec = 0 + soa_email = webmaster@import-example.com + status = active + ttl_sec = 0 + type = master +{{< /output >}} + +### Fill In Your Domain's Configuration Data + +As mentioned in the [Terraform’s Import Command](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#terraform-s-import-command) section, you must manually create your resource configurations when importing existing infrastructure. + +1. Fill in the configuration values for the `linode_domain` resource block. The necessary values for the example resource configuration file were collected from the output of the `terraform show` command applied in Step 2 of the [Import Your Domain to Terraform](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#import-your-domain-to-terraform) section. + + {{< file "linode_domain_example.tf" >}} +provider "linode" { + token = "1a2b3c..." +} + +resource "linode_domain" "example_label" { + domain = "import-example.com" + soa_email = "webmaster@import-example.com" + type = "master" +} + {{< /file >}} + + {{< note >}} + If your Domain `type` is `slave` then you'll need to include a `master_ips` argument with values set to the IP addresses that represent the Master DNS for your domain. + {{< /note >}} + +1. Check for errors in your configuration by running the `plan` command: + + terraform plan + + `terraform plan` shows you the changes that would take place if you were to apply the configurations with the `terraform apply` command. Running `terraform plan` should result in Terraform displaying that no changes are to be made. + +1. Once you have verified the configurations you provided in the `linode_domain` block, you are ready to begin managing your domain with Terraform. Any changes or updates can be made by updating your `linode_domain_example.tf` file, then verifying the changes with the `terrform plan` command, and then finally applying the changes with the `terraform apply` command. + + For more available configuration options, visit the [Linode Domain](https://www.terraform.io/docs/providers/linode/r/domain.html) Terraform documentation. + +## Import a Block Storage Volume to Terraform + +### Retrieve Your Block Storage Volume's ID + +1. Using the Linode CLI, retrieve a list of all your volumes to find the ID of the Block Storage Volume you would like to manage under Terraform: + + linode-cli volumes list --json --pretty + + You should see output similar to the following: + + {{< output >}} +[ +  { +    "id": 17045, +    "label": "import-example", +    "linode_id": 11426126, +    "region": "us-east", +    "size": 20, +    "status": "active" +  } +] +{{< /output >}} + + Find the Block Storage Volume you would like to import and copy down the ID. You will use this ID to import your volume to Terraform. + +### Create an Empty Resource Configuration + +1. Ensure you are in your Terraform project directory. Create a Terraform configuration file to manage the Block Storage Volume you will import in the next section. Your file can be named anything you like, but must end in `.tf`. Add a Linode provider block with your API access token and an empty `linode_volume` resource configuration block to the file: + + {{< file "linode_volume_example.tf" >}} +provider "linode" { + token = "Your API Token" +} + +resource "linode_volume" "example_label" {} +{{< /file >}} + +### Import Your Volume to Terraform + +1. Run the `import` command, supplying the `linode_volume` resource's label, and the volume ID that was retrieved in the [Retrieve Your Block Storage Volume's ID](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#retrieve-your-block-storage-volume-s-id) section: + + terraform import linode_volume.example_label volumeID + + You should see output similar to the following: + + {{< output >}} +linode_volume.example_label: Importing from ID "17045"... +linode_volume.example_label: Import complete! + Imported linode_volume (ID: 17045) +linode_volume.example_label: Refreshing state... (ID: 17045) + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +{{< /output >}} + + This command will create a `terraform.tfstate` file with information about your Volume. You will use this information to fill out your resource configuration. + +1. To view the information created by `terraform import`, run the `show` command. This command will display a list of key-value pairs representing information about the imported Volume: + + terraform show + + You should see output like the following: + + {{< output >}} +linode_volume.example_label: + id = 17045 + filesystem_path = /dev/disk/by-id/scsi-0Linode_Volume_import-example + label = import-example + linode_id = 11426126 + region = us-east + size = "20" + status = active +{{< /output >}} + +### Fill In Your Volume's Configuration Data + +As mentioned in the [Terraform’s Import Command](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#terraform-s-import-command) section, you must manually create your resource configurations when importing existing infrastructure. + +1. Fill in the configuration values for the `linode_volume` resource block. The necessary values for the example resource configuration file were collected from the output of the `terraform show` command applied in Step 2 of the [Import Your Volume to Terraform](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#import-your-volume-to-terraform) section: + + {{< file "linode_volume_example.tf" >}} +provider "linode" { + token = "1a2b3c..." +} + +resource "linode_volume" "example_label" { + label = "import-example" + region = "us-east" + size = "20" +} + {{< /file >}} + + {{< note >}} +Though it is not required, it's a good idea to include a configuration for the size of the volume so that it can be managed more easily should you ever choose to expand the Volume. It is not possible to reduce the size of a volume. + {{< /note >}} + +1. Check for errors in your configuration by running the `plan` command: + + terraform plan + + `terraform plan` shows you the changes that would take place if you were to apply the configurations with the `terraform apply` command. Running `terraform plan` should result in Terraform displaying that no changes are to be made. + +1. Once you have verified the configurations you provided in the `linode_volume` block, you are ready to begin managing your Block Storage Volume with Terraform. Any changes or updates can be made by updating your `linode_volume_example.tf` file, then verifying the changes with the `terrform plan` command, and then finally applying the changes with the `terraform apply` command. + + For more optional configuration options, visit the [Linode Volume](https://www.terraform.io/docs/providers/linode/r/volume.html) Terraform documentation. + +## Import a NodeBalancer to Terraform + +Configuring [Linode NodeBalancers](/docs/platform/nodebalancer/getting-started-with-nodebalancers/) with Terraform requires three separate resource configuration blocks: one to create the NodeBalancer, a second for the NodeBalancer Configuration, and a third for the NodeBalancer Nodes. + +### Retrieve Your NodeBalancer, NodeBalancer Config, NodeBalancer Node IDs + +1. Using the Linode CLI, retrieve a list of all your NodeBalancers to find the ID of the NodeBalancer you would like to manage under Terraform: + + linode-cli nodebalancers list --json --pretty + + You should see output similar to the following: + + {{< output >}} +[ +  { +    "client_conn_throttle": 0, +    "hostname": "nb-192-0-2-3.newark.nodebalancer.linode.com", +    "id": 40721, +    "ipv4": "192.0.2.3", +    "ipv6": "2600:3c03:1::68ed:945f", +    "label": "terraform-example", +    "region": "us-east" +  } +] +{{< /output >}} + + Find the NodeBalancer you would like to import and copy down the ID. You will use this ID to import your NodeBalancer to Terraform. + +1. Retrieve your NodeBalancer configuration by supplying the ID of the NodeBalancer you retrieved in the previous step: + + linode-cli nodebalancers configs-list 40721 --json --pretty + + You should see output similar to the following: + + {{< output >}} +[ +  { +    "algorithm": "roundrobin", +    "check_passive": true, +    "cipher_suite": "recommended", +    "id": 35876, +    "port": 80, +    "protocol": "http", +    "ssl_commonname": "", +    "ssl_fingerprint": "", +    "stickiness": "table" +  } +] +{{< /output >}} + + Copy down the ID of your NodeBalancer configuration, you will use it to import your NodeBalancer configuration to Terraform. + +1. Retrieve a list of Nodes corresponding to your NodeBalancer to find the label and address of your NodeBalancer Nodes. Supply the ID of your NodeBalancer as the first argument and the ID of your NodeBalancer configuration as the second: + + linode-cli nodebalancers nodes-list 40721 35876 --json --pretty + + You should see output like the following: + + {{< output >}} +[ +  { +    "address": "192.168.214.37:80", +    "id": 327539, +    "label": "terraform-import", +    "mode": "accept", +    "status": "UP", +    "weight": 100 +  } +] +{{< /output >}} + + If you are importing a NodeBalancer, chances are your output lists more than one Node. Copy down the IDs of each Node. You will use them to import your Nodes to Terraform. + +### Create Empty Resource Configurations + +1. Ensure you are in your Terraform project directory. Create a Terraform configuration file to manage the NodeBalancer you will import in the next section. Your file can be named anything you like, but must end in `.tf`. + + Add a Linode provider block with your API access token and empty `linode_nodebalancer`, `linode_nodebalancer_config`, and `linode_nodebalancer_node` resource configuration blocks to the file. Be sure to give the resources appropriate labels. These labels will be used to reference the resources locally within Terraform: + + {{< file "linode_nodebalancer_example.tf" >}} +provider "linode" { + token = "Your API Token" +} + +resource "linode_nodebalancer" "example_nodebalancer_label" {} + +resource "linode_nodebalancer_config" "example_nodebalancer_config_label" {} + +resource "linode_nodebalancer_node" "example_nodebalancer_node_label" {} +{{< /file >}} + + If you have more than one NodeBalancer Configuration, you will need to supply multiple `linode_nodebalancer_config` resource blocks with different labels. The same is true for each NodeBalancer Node requiring an additional `linode_nodebalancer_node` block. + +### Import Your NodeBalancer, NodeBalancer Configuration, and NodeBalancer Nodes to Terraform + +1. Run the `import` command for your NodeBalancer, supplying your local label and the ID of your NodeBalancer as the last parameter. + + terraform import linode_nodebalancer.example_nodebalancer_label nodebalancerID + + You should see output similar to the following: + + {{< output >}} +linode_nodebalancer.example_nodebalancer_label: Importing from ID "40721"... +linode_nodebalancer.example_nodebalancer_label: Import complete! + Imported linode_nodebalancer (ID: 40721) +linode_nodebalancer.example_nodebalancer_label: Refreshing state... (ID: 40721) + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +{{< /output >}} + +1. Run the `import` command for your NodeBalancer configuration, supplying your local label, and the ID of your NodeBalancer and the ID of your NodeBalancer configuration separated by commas as the last argument. + + terraform import linode_nodebalancer_config.example_nodebalancer_config_label nodebalancerID,nodebalancerconfigID + + You should see output similar to the following: + + {{< output >}} +linode_nodebalancer_config.example_nodebalancer_config_label: Importing from ID "40721,35876"... +linode_nodebalancer_config.example_nodebalancer_config_label: Import complete! + Imported linode_nodebalancer_config (ID: 35876) +linode_nodebalancer_config.example_nodebalancer_config_label: Refreshing state... (ID: 35876) + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +{{< /output >}} + +1. Run the `import` command for you NodeBalancer Nodes, supplying your local label, and the ID of your NodeBalancer, the ID of your NodeBalancer Configuration, and your NodeBalancer Node, separated by commas, as the last argument. + + terraform import linode_nodebalancer_node.example_nodebalancer_node_label nodebalancerID,nodebalancerconfigID,nodebalancernodeID + + + You should see output like the following: + + {{< output >}} +linode_nodebalancer_node.example_nodebalancer_node_label: Importing from ID "40721,35876,327539"... +linode_nodebalancer_node.example_nodebalancer_node_label: Import complete! + Imported linode_nodebalancer_node (ID: 327539) +linode_nodebalancer_node.example_nodebalancer_node_label: Refreshing state... (ID: 327539) + +Import successful! + +The resources that were imported are shown above. These resources are now in +your Terraform state and will henceforth be managed by Terraform. +{{< /output >}} + + +1. Running `terraform import` creates a `terraform.tfstate` file with information about your NodeBalancer. You will use this information to fill out your resource configuration. To view the information created by `terraform import`, run the `show` command: + + terraform show + + You should see output like the following: + + {{< output >}} +linode_nodebalancer.example_nodebalancer_label: + id = 40721 + client_conn_throttle = 0 + created = 2018-11-16T20:21:03Z + hostname = nb-192-0-2-3.newark.nodebalancer.linode.com + ipv4 = 192.0.2.3 + ipv6 = 2600:3c03:1::68ed:945f + label = terraform-example + region = us-east + transfer.% = 3 + transfer.in = 0.013627052307128906 + transfer.out = 0.0015048980712890625 + transfer.total = 0.015131950378417969 + updated = 2018-11-16T20:21:03Z + +linode_nodebalancer_config.example_nodebalancer_config_label: + id = 35876 + algorithm = roundrobin + check = none + check_attempts = 2 + check_body = + check_interval = 5 + check_passive = true + check_path = + check_timeout = 3 + cipher_suite = recommended + node_status.% = 2 + node_status.down = 0 + node_status.up = 1 + nodebalancer_id = 40721 + port = 80 + protocol = http + ssl_commonname = + ssl_fingerprint = + ssl_key = + stickiness = table + +linode_nodebalancer_node.example_nodebalancer_node_label: + id = 327539 + address = 192.168.214.37:80 + config_id = 35876 + label = terraform-import + mode = accept + nodebalancer_id = 40721 + status = UP + weight = 100 +{{< /output >}} + +### Fill In Your NodeBalancer's Configuration Data + +As mentioned in the [Terraform’s Import Command](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#terraform-s-import-command) section, you must manually create your resource configurations when importing existing infrastructure. + +1. Fill in the configuration values for all three NodeBalancer resource configuration blocks. The necessary values for the example resource configuration file were collected from the output of the `terraform show` command applied in Step 4 of the [Import Your NodeBalancer, NodeBalancer Configuration, and NodeBalancer Nodes to Terraform](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#import-your-nodebalancer-nodebalancer-configuration-and-nodebalancer-nodes-to-terraform) section: + +{{< file "linode_nodebalancer_example.tf" >}} +provider "linode" { + token = "1a2b3c..." +} + +resource "linode_nodebalancer" "nodebalancer_import" { + label = "terraform-example" + region = "us-east" +} + +resource "linode_nodebalancer_config" "nodebalancer_config_import" { + nodebalancer_id = "40721" +} + +resource "linode_nodebalancer_node" "nodebalancer_node_import" { + label = "terraform-import" + address = "192.168.214.37:80" + nodebalancer_id = "40721" + config_id = "35876" +} +{{< /file >}} + +1. Check for errors in your configuration by running the `plan` command: + + terraform plan + + `terraform plan` shows you the changes that would take place if you were to apply the configurations with the `terraform apply` command. Running `terraform plan` should result in Terraform displaying that no changes are to be made. + +1. Once you have verified the configurations you provided in all three NodeBalancer configuration blocks, you are ready to begin managing your NodeBalancers with Terraform. Any changes or updates can be made by updating your `linode_nodebalancer_example.tf` file, then verifying the changes with the `terrform plan` command, and finally, applying the changes with the `terraform apply` command. + + For more available configuration options, visit the [Linode NodeBalancer](https://www.terraform.io/docs/providers/linode/r/nodebalancer.html), [Linode NodeBalancer Config](https://www.terraform.io/docs/providers/linode/r/nodebalancer_config.html), and [Linode NodeBalancer Node](https://www.terraform.io/docs/providers/linode/r/nodebalancer_node.html) Terraform documentation. + +## Next Steps + +You can follow a process similar to what has been outlined in this guide to begin importing other pieces of your Linode infrastructure such as images, SSH keys, access tokens, and StackScripts. Check out the links in the [More Information](/docs/applications/configuration-management/import-existing-infrastructure-to-terraform/#more-information) section below for helpful information. diff --git a/docs/applications/configuration-management/introduction-to-hcl/index.md b/docs/applications/configuration-management/introduction-to-hcl/index.md new file mode 100644 index 00000000000..42dafe1f8af --- /dev/null +++ b/docs/applications/configuration-management/introduction-to-hcl/index.md @@ -0,0 +1,285 @@ +--- +author: + name: Linode + email: docs@linode.com +description: 'This guides provides an introduction to HCL syntax and commonly used HCL terminology.' +keywords: ["terraform", "hcl", "hashicorp", "orchestration"] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +modified: 2018-12-12 +modified_by: + name: Linode +published: 2018-12-12 +title: Introduction to HashiCorp Configuration Language (HCL) +external_resources: + - '[HCL on GitHub](https://github.com/hashicorp/hcl)' + - '[Terraform Official Documentation - Configuration Syntax](https://www.terraform.io/docs/configuration/syntax.html)' +--- + +HCL is a configuration language authored by [HashiCorp](https://www.hashicorp.com/). HCL is used with HashiCorp's cloud infrastructure automation tools, like [Terraform](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/). The language was created with the goal of being both human and machine friendly. It is JSON compatible, which means it is interoperable with other systems outside of the Terraform product line. + +This guide provides an introduction to HCL syntax and some commonly used HCL terminology. + +## HCL Syntax Overview + +HashiCorp's configuration syntax is easy to read and write. It was created to have a more clearly visible and defined structure when compared with other well known configuration languages, like YAML. + +{{< file "~/terraform/main.tf">}} +# Linode provider block. Installs Linode plugin. +provider "linode" { + token = "${var.token}" +} + +variable "region" { + description = "This is the location where the Linode instance is deployed." +} + +/* A multi + line comment. */ +resource "linode_instance" "example_linode" { + image = "linode/ubuntu18.04" + label = "example-linode" + region = "${var.region}" + type = "g6-standard-1" + authorized_keys = [ "my-key" ] + root_pass = "example-password" +} + {{}} + +{{< note >}} +You should not include sensitive data in your resource declarations. For more information on secrets management, see [Secrets Management with Terraform](/docs/applications/configuration-management/secrets-management-with-terraform/). +{{}} + +### Key Elements of HCL + +- HCL syntax is composed of *stanzas* or *blocks* that define a variety of configurations available to Terraform. [Provider plugins](https://www.terraform.io/docs/configuration/providers.html) expand on the available base Terraform configurations. + +- Stanzas or blocks are comprised of `key = value` pairs. Terraform accepts values of type string, number, boolean, map, and list. + +- Single line comments start with `#`, while multi-line comments use an opening `/*` and a closing `*/`. + +- [Interpolation syntax](https://www.terraform.io/docs/configuration/interpolation.html) can be used to reference values stored outside of a configuration block, like in an [input variable](#input-variables), or from a [Terraform module](#modules)'s output. + + An interpolated variable reference is constructed with the `"${var.region}"` syntax. This example references a variable named `region`, which is prefixed by `var.`. The opening `${` and closing `}` indicate the start of interpolation syntax. + +- You can include multi-line strings by using an opening `<}} +provider "linode" { + token = "my-token" +} +{{}} + +Once your provider is declared, you can begin configuring resources available from the provider. + +{{< note >}} +Providers are packaged as plugins for Terraform. Whenever declaring a new provider in your Terraform configuration files, the `terraform init` command should be run. This command will complete several initialization steps that are necessary before you can apply your Terraform configuration, including downloading the plugins for any providers you've specified. +{{}} + +## Resources + +A Terraform *resource* is any component of your infrastructure that can be managed by your provider. Resources available with the Linode provider range from a Linode instance, to a block storage volume, to a DNS record. Terraform's [Linode Provider](https://www.terraform.io/docs/providers/linode/index.html) documentation contains a full listing of all supported resources. + +Resources are declared with a resource block in a `.tf` configuration file. This example block deploys a 2GB Linode instance located in the US East data center from an Ubuntu 18.04 image. Values are also provided for the Linode's label, public SSH key, and root password: + +{{< file "~/terraform/main.tf" >}} +resource "linode_instance" "WordPress" { + image = "linode/ubuntu18.04" + label = "WPServer" + region = "us-east" + type = "g6-standard-1" + authorized_keys = [ "example-key" ] + root_pass = "example-root-pass" +} +{{}} + +HCL-specific [meta-parameters](https://www.terraform.io/docs/configuration/resources.html#meta-parameters) are available to all resources and are independent of the provider you use. Meta-parameters allow you to do things like customize the lifecycle behavior of the resource, define the number of resources to create, or protect certain resources from being destroyed. See Terraform's [Resource Configuration](https://www.terraform.io/docs/configuration/resources.html) documentation for more information on meta-parameters. + +## Modules + +A *module* is an encapsulated set of Terraform configurations used to organize the creation of resources in reusable configurations. + +The [Terraform Module Registry](https://registry.terraform.io/) is a repository of community modules that can help you get started creating resources for various providers. You can also create your own modules to better organize your Terraform configurations and make them available for reuse. Once you have created your modules, you can distribute them via a remote version control repository, like GitHub. + +### Using Modules + +A module block instructs Terraform to create an instance of a module. This block instantiates any resources defined within that module. + +The only universally required configuration for all module blocks is the `source` parameter which indicates the location of the module's source code. All other required configurations will vary from module to module. If you are using a local module you can use a relative path as the `source` value. The source path for a Terraform Module Registry module will be available on the module's registry page. + +This example creates an instance of a module named `linode-module-example` and provides a relative path as the location of the module's source code: + +{{< file "~/terraform/main.tf" >}} +module "linode-module-example" { + source = "/modules/linode-module-example" +} +{{}} + +Authoring modules involves defining resource requirements and parameterizing configurations using [input variables](#input-variables), variable files, and outputs. To learn how to write your own Terraform modules, see [Create a Terraform Module](/docs/applications/configuration-management/create-terraform-module/). + +## Input Variables + +You can define *input variables* to serve as Terraform configuration parameters. By convention, input variables are normally defined within a file named `variables.tf`. Terraform will load all files ending in `.tf`, so you can also define variables in files with other names. + +- Terraform accepts variables of type string, number, boolean, map, and list. If a variable type is not explicitly defined, Terraform will default to `type = "string"`. + +- It is good practice to provide a meaningful `description` for all your input variables. + +- If a variable does not contain a `default` value, or if you would like to override a variable's default value, you must provide a value as an environment variable or within a variable values file. + +### Variable Declaration Example + +{{< file "~/terraform/variables.tf" >}} +variable "token" { + description = "This is your Linode APIv4 Token." +} + +variable "region" { + description: "This is the location where the Linode instance is deployed." + default = "us-east" +} +{{}} + +Two input variables named `token` and `region` are defined, respectively. The `region` variable defines a `default` value. Both variables will default to `type = "string"`, since a type is not explicitly declared. + +### Supplying Variable Values + +Variable values can be specified in `.tfvars` files. These files use the same syntax as Terraform configuration files: + +{{< file "~/terraform/terraform.tfvars" >}} +token = "my-token" +region = "us-west" +{{}} + +Terraform will automatically load values from filenames which match `terraform.tfvars` or `*.auto.tfvars`. If you store values in a file with another name, you need to specify that file with the `-var-file` option when running `terraform apply`. The `-var-file` option can be invoked multiple times: + + terraform apply \ + -var-file="variable-values-1.tfvars" \ + -var-file="variable-values-2.tfvars" + +Values can also be specified in environment variables when running `terraform apply`. The name of the variable should be prefixed with `TF_VAR_`: + + TF_VAR_token=my-token-value TF_VAR_region=us-west terraform apply + +{{< note >}} +Environment variables can only assign values to variables of `type = "string"` +{{}} + +### Referencing Variables + +You can call existing input variables within your configuration file using Terraform's interpolation syntax. Observe the value of the `region` parameter: + +{{< file "~/terraform/main.tf" >}} +resource "linode_instance" "WordPress" { + image = "linode/ubuntu18.04" + label = "WPServer" + region = "${var.region}" + type = "g6-standard-1" + authorized_keys = [ "example-key" ] + root_pass = "example-root-pass" +} +{{}} + +{{< note >}} +If a variable value is not provided in any of the ways discussed above, and the variable is called in a resource configuration, Terraform will prompt you for the value when you run `terraform apply`. +{{}} + +For more information on variables, see Terraform's [Input Variables](https://www.terraform.io/intro/getting-started/variables.html) documentation. + +## Interpolation + +HCL supports the [interpolation](https://en.wikipedia.org/wiki/String_interpolation) of values. Interpolations are wrapped in an opening `${` and a closing `}`. Input variable names are prefixed with `var.`: + +{{< file "~/terraform/terraform.tf" >}} +provider "linode" { + token = "${var.token}" +} +{{}} + +Interpolation syntax is powerful and includes the ability to reference attributes of other resources, call built-in functions, and use conditionals and templates. + +This resource's configuration uses a conditional to provide a value for the `tags` parameter: + +{{< file "~/terraform/terraform.tf" >}} +resource "linode_instance" "web" { + tags = ["${var.env == "production" ? var.prod_subnet : var.dev_subnet}"] +} +{{< /file >}} + +If the `env` variable has the value `production`, then the `prod_subnet` variable is used. If not, then the variable `dev_subent` is used. + +### Functions + +Terraform has built-in computational functions that perform a variety of operations, including reading files, concatenating lists, encrypting or creating a checksum of an object, and searching and replacing. + +{{< file "~/terraform/terraform.tf" >}} +resource "linode_sshkey" "main_key" { + label = "foo" + ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}" +} +{{}} + +In this example, `ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}"` uses Terraform’s built-in function `file()` to provide a local file path to the public SSH key’s location. The `chomp()` function removes trailing new lines from the SSH key. Observe that the nested functions are wrapped in opening `${` and closing `}` to indicate that the value should be interpolated. + +{{< note >}} +Running `terraform console` creates an environment where you can test interpolation functions. For example: + + terraform console + +{{< output >}} +> list("newark", "atlanta", "dallas") +[ + "newark", + "atlanta", + "dallas", +] +> +{{< /output >}} +{{< /note >}} + +Terraform's official documentation includes a complete list of [supported built-in functions](https://www.terraform.io/docs/configuration/interpolation.html#supported-built-in-functions). + +### Templates + +Templates can be used to store large strings of data. The template provider exposes the data sources for other Terraform resources or outputs to consume. The data source can be a file or an inline template. + +The data source can use Terraform's standard interpolation syntax for variables. The template is then rendered with variable values that you supply in the data block. + +This example template resource substitutes in the value from `${linode_instance.web.ip_address}` anywhere `${web_ip}` appears inside the template file `ips.json`: + +{{< file >}} +data "template_file" "web" { + template = "${file("${path.module}/ips.json")}" + + vars { + web_ip = "${linode_instance.web.ip_address}" + } +} +{{< /file >}} + +You could then define an [*output variable*](https://learn.hashicorp.com/terraform/getting-started/outputs.html) to view the rendered template when you later run `terraform apply`: + +{{< file >}} +output "ip" { + value = "${data.template_file.web.rendered}" +} +{{< /file >}} + +Terraform's official documentation has a list of [all available components](https://www.terraform.io/docs/configuration/interpolation.html) of interpolation syntax. + +## Next Steps + +Now that you are familiar with HCL, you can begin creating your own Linode instance with Terraform by following the [Use Terraform to Provision Linode Environments](/docs/applications/configuration-management/how-to-build-your-infrastructure-using-terraform-and-linode/) guide. diff --git a/docs/applications/configuration-management/secrets-management-with-terraform/index.md b/docs/applications/configuration-management/secrets-management-with-terraform/index.md new file mode 100644 index 00000000000..9d95d186979 --- /dev/null +++ b/docs/applications/configuration-management/secrets-management-with-terraform/index.md @@ -0,0 +1,164 @@ +--- +author: + name: Linode + email: docs@linode.com +description: 'How to Manage Secrets with Terraform' +keywords: ['terraform','secrets','secrets management','backend','hcl'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-12 +modified: 2018-12-12 +modified_by: + name: Linode +title: "Secrets Management with Terraform" +contributor: + name: Linode +external_resources: +- '[Terraform Input Variable Configuration](https://www.terraform.io/docs/configuration/variables.html)' +- '[Terraform Backend Configuration](https://www.terraform.io/docs/backends/config.html)' +- '[Terraform Backend Types](https://www.terraform.io/docs/backends/types/index.html)' +- '[Terraform State Storage and Locking](https://www.terraform.io/docs/backends/state.html)' +- '[GitHub Discussion - Storing Sensitive Values in State Files](https://github.com/hashicorp/terraform/issues/516)' +--- + +Terraform is an Infrastructure as Code (IaC) tool that allows you to write declarative code to manage your infrastructure. In order to implement IaC with Terraform it is necessary to supply secrets, such as server passwords and API tokens, within your code. This guide will discuss methods for securing those secrets within Terraform. + +## Keeping Secrets Out of .tf Files + +In Terraform, `.tf` files contain the declarative code used to create, manage, and destroy infrastructure. This code is often committed to a version control system like Git, using a platform like GitHub, and shared within a team. Because it is easy for this information to become public-facing, it is important that you make sure your committed code is free of secrets. + +### Input Variables + +Terraform configurations in `.tf` files can accept values from [*input variables*](https://www.terraform.io/docs/configuration/variables.html). These variables are included in your configuration using Terraform's [interpolation syntax](https://www.terraform.io/docs/configuration/interpolation.html). + +For example, you might have a `linode-infrastructure.tf` file with a provider block that requires an API access token. The `token` variable definition is declared inside your `.tf` file and is then interpolated inside the provider declaration with the `"${var.token}"` syntax: + +{{< file "linode-infrastructure.tf" >}} +variable "token" { + description = "Your API access token" +} + +provider "linode" { + token = "${var.token}" +} +{{< /file >}} + +Variable definitions are written in `.tf` files. In this example, it's the same file as your provider configuration, but the definition could have been in a separate `.tf` file too. + +{{< note >}} +Your variable definitions can have default values assigned to them. Here's an example that encodes Linode's Newark data center as the default value for a `region` variable: + +{{< file "variables.tf" >}} +variable "region" { + description = "The region to deploy Linode instances in" + default = "us-east" +} +{{< /file >}} + +You could later use this variable when declaring your Linode instances. +{{< /note >}} + +### Assigning Variable Values in a File + +The values assigned to your variables (aside from default values) are not included in the variable definitions in your `.tf` files. Instead, the values are stored in separate files with the `.tfvars` extension. When Terraform runs a command like `plan` or `apply`, it automatically looks through the working directory for a file named `terraform.tfvars`, or for files with the `.auto.tfvars` extension. + +Here's an example `terraform.tfvars` which supplies a value for the `token` variable from the previous example: + +{{< file "terraform.tfvars" >}} +token = 'your-token-value' +{{< /file >}} + +You would then add the `terraform.tfvars` file to your `.gitignore` file and keep it out of version control. This strategy allows you to safely commit the `linode-infrastructure.tf` file. + +For ease of use with large `terraform.tfvars` files, it might be beneficial to include an example `terraform.tfvars.example` in your Git repository with all of the variable names recorded (but none of the values entered). Team members could then copy this example into their local repository's `terraform.tfvars` and enter the appropriate values. + +{{< note >}} +Variable value files with names that don't match `terraform.tfvars` or `*.auto.tfvars` can be specified with the `-var-file` option: + + terraform apply -var-file=myvars.tfvars + +Supplying multiple `.tfvars` files is another way to further separate secret variables and non-secret variables; e.g.: + + terraform apply \ + -var-file=non-secret-variables.tfvars \ + -var-file=secret-variables.tfvars + +{{< /note >}} + +### Assigning Values in Environment Variables + +Terraform allows you to keep input variable values in environment variables. These variables have the prefix `TF_VAR_` and are supplied at the command line. Using the above example of an API access token, you could export the variable and use it like so: + + export TF_VAR_token=your-token-value + terraform apply + +You could also include the variable on the same line when running `terraform plan` or `terraform apply`: + + TF_VAR_token=your-token-value terraform apply + +{{< caution >}} +This method commits the environment variable to your shell's history, so take care when using this method. +{{< /caution >}} + +### Assigning Values in Command-Line Flags + +Variable values can be set with the `-var` option: + + terraform apply -var 'token=your-token-value' + +{{< caution >}} +This method commits the command-line variable to your shell's history, so take care when using this method. +{{< /caution >}} + +### Supply Variables at Prompt + +If Terraform does not find a default value for a defined variable; or a value from a `.tfvars` file, environment variable, or CLI flag; it will prompt you for a value before running an action: + +{{< output >}} +$ terraform plan +var.token + Your API access token + + Enter a value: +{{< /output >}} + +This method is a bit easier to use than supplying environment variables, and has the added benefit of displaying the description you set up when defining your variable. + +## How to Manage Your State File + +While it is relatively easy to keep secrets out of `.tf` files using any of the above methods, there is another file you need to be aware of when managing secrets, and that is the `terraform.tfstate` file. + +This *state file* contains a JSON object that holds your managed infrastructure's current state. This state is a snapshot of the various attributes of your infrastructure at the time it was last modified. It is generated on `terraform apply` and is a necessary part of the Terraform process, as it maps the declarative code of your `.tf` files to your real world infrastructure. + +As of the writing of this guide, **sensitive information used to generate your Terraform state can be stored as plain text in the `terraform.tfstate` file.** For example, if you are working with the Linode provider and have supplied a root password for your Linode instance, that root password will be stored as plain text in the state file. **Avoid checking your `terraform.tfstate` file into your version control repository.** Instead, the following are some strategies for storing and sharing your state files. + +### Remote Backends + +Terraform [*backends*](https://www.terraform.io/docs/backends/index.html) allow the user to securely store their state in a remote location, such as a key/value store like [Consul](https://www.consul.io/), or an S3 compatible bucket storage like [Minio](https://www.minio.io/). This allows the Terraform state to be read from the remote store, and because the state only ever exists locally in memory, there is no worry about storing secrets in plain text. + +Some backends, like Consul, also allow for state locking. If one user is applying a state, another user will be unable to make any changes. + +Using a Terraform backend is the preferred way to share a Terraform state file. + +### Encrypting Secrets + +Third-party tools exist that allow you to encrypt your secrets. If you encrypt the secrets in your `terraform.tfstate` (or your `.tfvars` files), you can check them into version control securely: + +- [git-crypt](https://github.com/AGWA/git-crypt) allows you to encrypt files when they are committed to a Git repository. git-crypt also decrypts files when they are checked out. + + {{< note >}} +You must initialize git-crypt in a repository before committing your state file or variable value files, or they will not be eligible for encryption. +{{< /note >}} + +- [Terrahelp](https://github.com/opencredo/terrahelp) allows you to encrypt and decrypt a whole state file, or just the variables you have include in your `terraform.tfvars` file. + +### Use a Dummy Password + +It is possible to supply a dummy password to Terraform and later change that password manually to a more secure one. For instance, if you were to create a Linode instance with a dummy root password, you could later change that password from the command line or in the Linode Manager. + +{{< note >}} +Any attempt to change the password in a `.tf` file will result in the creation of new resources on `terraform apply`. +{{< /note >}} + +### Privatize Version Control + +If you are unwilling or unable to use the above options to help manage your state file, and if you are using a platform like GitHub or GitLab to share your state files, then at minimum the repository should be private. diff --git a/docs/applications/configuration-management/test-salt-locally-with-kitchen-salt/index.md b/docs/applications/configuration-management/test-salt-locally-with-kitchen-salt/index.md index 00df04a1196..b3e52c5b7a2 100644 --- a/docs/applications/configuration-management/test-salt-locally-with-kitchen-salt/index.md +++ b/docs/applications/configuration-management/test-salt-locally-with-kitchen-salt/index.md @@ -6,7 +6,7 @@ description: 'Test Salt states locally with Kitchen and kitchen-salt.' keywords: ['saltstack','salt','kitchen','kitchen-salt','kitchensalt','salt solo','saltsolo'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' published: 2018-10-15 -modified: 2018-10-15 +modified: 2018-12-14 modified_by: name: Linode title: "Test Salt States Locally with KitchenSalt" @@ -212,4 +212,4 @@ verifier: name: inspec {{< /file >}} -For more information on writing tests, visit the links in the More Information section below. \ No newline at end of file +For more information on writing tests, visit the links in the More Information section below. diff --git a/docs/applications/containers/deploy-a-flask-application-with-dokku/index.md b/docs/applications/containers/deploy-a-flask-application-with-dokku/index.md index f4328e00038..544bf36e98e 100644 --- a/docs/applications/containers/deploy-a-flask-application-with-dokku/index.md +++ b/docs/applications/containers/deploy-a-flask-application-with-dokku/index.md @@ -7,7 +7,7 @@ og_description: 'Host your own PaaS with Dokku, a highly extensible way to deplo keywords: ['docker','containers','nginx', 'heroku', 'PaaS', 'git', 'Platform-as-a-service', 'Platform As a Service'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' published: 2018-03-07 -modified: 2018-03-07 +modified: 2018-12-14 modified_by: name: Linode title: "Deploy a Flask Application with Dokku" diff --git a/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/Docker_Commands_Quick_Reference_Cheat_Sheet_smg.png b/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/Docker_Commands_Quick_Reference_Cheat_Sheet_smg.png new file mode 100644 index 00000000000..e7513c67aa4 Binary files /dev/null and b/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/Docker_Commands_Quick_Reference_Cheat_Sheet_smg.png differ diff --git a/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/index.md b/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/index.md index f0a54fc9e9c..1bd89dcbf4f 100644 --- a/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/index.md +++ b/docs/applications/containers/docker-commands-quick-reference-cheat-sheet/index.md @@ -6,7 +6,7 @@ description: 'A quick reference cheat sheet on Docker commands for installation, keywords: ["docker", "quick reference", "cheat sheet", "commands"] aliases: ['applications/containers/docker-quick-reference-cheat-sheet/'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2017-11-20 +modified: 2018-12-18 modified_by: name: Linode published: 2015-03-30 @@ -15,6 +15,8 @@ external_resources: - '[Docker Cheat Sheet (Github)](https://github.com/wsargent/docker-cheat-sheet)' --- +![Docker Commands Quick Reference Cheat Sheet](Docker_Commands_Quick_Reference_Cheat_Sheet_smg.png "Docker Commands Quick Reference Cheat Sheet") + Docker is becoming increasingly popular among software developers, operators and enterprises as a software container platform. Containers package software in a format that can run isolated on a host operating system. Bundled with only essential libraries and settings, Docker renders lightweight, efficient, self-contained systems that run identically wherever deployed. Optimizing the platform's functionality begins with mastery of the core Docker commands. This cheat sheet is a reference for the most basic Docker commands that address installation, Hub interaction, and working with containers and images. diff --git a/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/Install_Subsonic_Media_Server_on_Ubuntu_or_Debian_smg.png b/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/Install_Subsonic_Media_Server_on_Ubuntu_or_Debian_smg.png new file mode 100644 index 00000000000..21dbbfab1a3 Binary files /dev/null and b/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/Install_Subsonic_Media_Server_on_Ubuntu_or_Debian_smg.png differ diff --git a/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/index.md b/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/index.md index da025371361..6e349e45996 100644 --- a/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/index.md +++ b/docs/applications/media-servers/install-subsonic-media-server-on-ubuntu-or-debian/index.md @@ -7,7 +7,7 @@ og_description: 'Subsonic is a free music streaming application. This guide show keywords: ["subsonic", "music", "audio", "streaming", "media server"] aliases: ['applications/media-servers/subsonic/'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2018-04-26 +modified: 2018-12-18 modified_by: name: Linode published: 2015-02-02 @@ -16,6 +16,8 @@ external_resources: - '[Subsonic official site](http://www.subsonic.org)' --- +![Install Subsonic Media Server on Ubuntu or Debian to Stream Music Through Your Linode](Install_Subsonic_Media_Server_on_Ubuntu_or_Debian_smg.png "Install Subsonic Media Server on Ubuntu or Debian to Stream Music Through Your Linode") + ## What is Subsonic? [Subsonic](http://subsonic.org) is an easy-to-use media streaming service with a user-friendly interface and the ability to share music and video with multiple users. It is highly customizable and includes features such as Chromecast support and file conversion. diff --git a/docs/audiences/_index.md b/docs/audiences/_index.md new file mode 100644 index 00000000000..3542633f4bb --- /dev/null +++ b/docs/audiences/_index.md @@ -0,0 +1,4 @@ +--- +title: Audiences +description: "View development guides based on audience experience level." +--- diff --git a/docs/audiences/beginner/_index.md b/docs/audiences/beginner/_index.md new file mode 100644 index 00000000000..b76f1384957 --- /dev/null +++ b/docs/audiences/beginner/_index.md @@ -0,0 +1,3 @@ +--- +title: Beginner +--- diff --git a/docs/audiences/foundational/_index.md b/docs/audiences/foundational/_index.md new file mode 100644 index 00000000000..5bb57cb618a --- /dev/null +++ b/docs/audiences/foundational/_index.md @@ -0,0 +1,3 @@ +--- +title: Foundational +--- diff --git a/docs/audiences/intermediate/_index.md b/docs/audiences/intermediate/_index.md new file mode 100644 index 00000000000..a0daf61cf69 --- /dev/null +++ b/docs/audiences/intermediate/_index.md @@ -0,0 +1,3 @@ +--- +title: Intermediate +--- diff --git a/docs/concentrations/_index.md b/docs/concentrations/_index.md new file mode 100644 index 00000000000..5decf1c3fa6 --- /dev/null +++ b/docs/concentrations/_index.md @@ -0,0 +1,4 @@ +--- +title: Concentrations +description: "Select a development concentration to view all related guides." +--- diff --git a/docs/concentrations/scientific-computing-and-big-data/_index.md b/docs/concentrations/scientific-computing-and-big-data/_index.md new file mode 100644 index 00000000000..d429a978d95 --- /dev/null +++ b/docs/concentrations/scientific-computing-and-big-data/_index.md @@ -0,0 +1,3 @@ +--- +title: Scientific Computing and Big Data +--- diff --git a/docs/concentrations/scripting-automation-and-build-tools/_index.md b/docs/concentrations/scripting-automation-and-build-tools/_index.md new file mode 100644 index 00000000000..fa38c4d7309 --- /dev/null +++ b/docs/concentrations/scripting-automation-and-build-tools/_index.md @@ -0,0 +1,3 @@ +--- +title: Scripting, Automation, and Build Tools +--- diff --git a/docs/concentrations/web-applications/_index.md b/docs/concentrations/web-applications/_index.md new file mode 100644 index 00000000000..7698dc09045 --- /dev/null +++ b/docs/concentrations/web-applications/_index.md @@ -0,0 +1,3 @@ +--- +title: Web Applications +--- diff --git a/docs/databases/mariadb/configure-wordpress-remote-database/Configure_WordPress_to_use_a_Remote_Database_smg.jpg b/docs/databases/mariadb/configure-wordpress-remote-database/Configure_WordPress_to_use_a_Remote_Database_smg.jpg new file mode 100644 index 00000000000..effe1512552 Binary files /dev/null and b/docs/databases/mariadb/configure-wordpress-remote-database/Configure_WordPress_to_use_a_Remote_Database_smg.jpg differ diff --git a/docs/databases/mariadb/configure-wordpress-remote-database/index.md b/docs/databases/mariadb/configure-wordpress-remote-database/index.md index 86b69354b7e..4b0f442faa6 100644 --- a/docs/databases/mariadb/configure-wordpress-remote-database/index.md +++ b/docs/databases/mariadb/configure-wordpress-remote-database/index.md @@ -5,7 +5,7 @@ author: description: 'This guide shows how to configure WordPress to access a database on a separate Linode.' keywords: ["mariadb", "database", "mysql", "remote database", "remote db", "remote client"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2018-06-25 +modified: 2018-12-11 modified_by: name: Linode published: 2018-06-25 @@ -16,6 +16,8 @@ external_resources: - '[MariaDB SQL commands](https://mariadb.com/kb/en/sql-commands/)' --- +![Configure WordPress to use a Remote Database](Configure_WordPress_to_use_a_Remote_Database_smg.jpg) + ## Before You Begin - This guide uses two Linodes in the same data center to communicate via [private IP](/docs/networking/remote-access/#adding-private-ip-addresses) addresses. You will need to configure a [LEMP](/docs/web-servers/lemp/) or [LAMP](/docs/web-servers/lamp/) stack on one. diff --git a/docs/databases/mysql/configure-master-master-mysql-database-replication/index.md b/docs/databases/mysql/configure-master-master-mysql-database-replication/index.md index 00fb3afe840..8b543e4ae11 100644 --- a/docs/databases/mysql/configure-master-master-mysql-database-replication/index.md +++ b/docs/databases/mysql/configure-master-master-mysql-database-replication/index.md @@ -7,7 +7,7 @@ og_description: 'MySQL Master-Master replication adds speed and redundancy. With keywords: ["set up mysql", "replication", "master-master", "high availability"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' aliases: ['databases/mysql/backup-options/', 'databases/mysql/mysql-master-master/', 'databases/mysql/mysql-master-master-replication/'] -modified: 2017-10-10 +modified: 2018-12-18 modified_by: name: Linode published: 2014-12-24 @@ -25,16 +25,20 @@ MySQL Master-Master replication adds speed and redundancy for active websites. W {{< note >}} This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you're not familiar with the `sudo` command, you can check our [Users and Groups](/docs/tools-reference/linux-users-and-groups) guide. -This guide is written for Debian 7 or Ubuntu 14.04. +This guide is written for Debian 9 or Ubuntu 18.04. {{< /note >}} ## Install MySQL -Use the following commands to install MySQL on each of the Linodes: +1. Use the following commands to install MySQL on each of the Linodes: - sudo apt-get update - sudo apt-get upgrade -y - sudo apt-get install mysql-server mysql-client + sudo apt-get update + sudo apt-get upgrade -y + sudo apt-get install mysql-server mysql-client + +2. Run the MySQL secure installation command. You will be asked to create a root password. It is recommended you select yes to all of the questions: + + mysql_secure_installation ## Edit MySQL's Configuration @@ -43,6 +47,7 @@ Use the following commands to install MySQL on each of the Linodes: **Server 1:** {{< file "/etc/mysql/my.cnf" >}} +[mysqld] server_id = 1 log_bin = /var/log/mysql/mysql-bin.log log_bin_index = /var/log/mysql/mysql-bin.log.index @@ -60,6 +65,7 @@ auto-increment-offset = 1 **Server 2:** {{< file "/etc/mysql/my.cnf" >}} +[mysqld] server_id = 2 log_bin = /var/log/mysql/mysql-bin.log log_bin_index = /var/log/mysql/mysql-bin.log.index @@ -74,7 +80,7 @@ auto-increment-offset = 2 {{< /file >}} -2. For each of the Linodes, edit the `bind-address` configuration in order to use the private IP addresses: +2. Edit the `bind-address` configuration in order to use the private IP addresses, for each of the Linodes. {{< file "/etc/mysql/my.cnf" >}} bind-address = x.x.x.x @@ -84,7 +90,7 @@ bind-address = x.x.x.x 3. Once completed, restart the MySQL application: - sudo service mysql restart + sudo systemctl restart mysql ## Create Replication Users diff --git a/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/Connect_Metabase_with_MySQL_for_Data_Exploration_smg.jpg b/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/Connect_Metabase_with_MySQL_for_Data_Exploration_smg.jpg new file mode 100644 index 00000000000..f01a0ce7a1a Binary files /dev/null and b/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/Connect_Metabase_with_MySQL_for_Data_Exploration_smg.jpg differ diff --git a/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/index.md b/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/index.md index ebcea3a1c21..d534e75607a 100644 --- a/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/index.md +++ b/docs/databases/mysql/connect-metabase-with-mysql-for-data-exploration/index.md @@ -6,7 +6,7 @@ description: 'Metabase is a data exploration tool that makes analytics accessibl og_description: 'Metabase provides a clean interface to query data on your browser. Metabase offers functionality to analyze data without SQL, create dashboards, and track metrics. This guide shows how to connect MySQL to Metabase then deploy on NGINX through a reverse proxy' keywords: ["visualization", "database", "query", "What is Metabase", "metabase", "mysql"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2018-02-22 +modified: 2018-12-10 modified_by: name: Linode published: 2018-02-22 @@ -17,6 +17,8 @@ external_resources: - '[Employees Testing Database](https://github.com/datacharmer/test_db)' --- +![Connect Metabase with mysql for data exploration](Connect_Metabase_with_MySQL_for_Data_Exploration_smg.jpg) + ## What is Metabase Metabase provides an interface to query data on your browser. In addition to supporting SQL querying, Metabase offers functionality to analyze data without SQL, create dashboards, and track metrics. This guide shows how to connect MySQL to Metabase then deploy on NGINX through a reverse proxy. diff --git a/docs/databases/mysql/deploy-mysql-workbench-for-database-administration/index.md b/docs/databases/mysql/deploy-mysql-workbench-for-database-administration/index.md index fb6d2648665..2069883ecce 100644 --- a/docs/databases/mysql/deploy-mysql-workbench-for-database-administration/index.md +++ b/docs/databases/mysql/deploy-mysql-workbench-for-database-administration/index.md @@ -7,7 +7,7 @@ og_description: 'MySQL Workbench is a graphical tool for working with MySQL data keywords: ["MySQL", "MySQL Workbench", "workbench", "administer database"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' published: 2015-12-04 -modified: 2017-08-01 +modified: 2018-12-10 modified_by: name: Linode title: 'Install MySQL Workbench for Database Administration' @@ -79,6 +79,10 @@ The first step after running MySQL Workbench is to add your Linode as a database * Default Schema - This is the default database to connect to. It's OK to leave this blank if you haven't created a database yet or don't want one to load by default. + {{< note >}} +Using MySQL Workbench (currently release 8.0.13) with multi-factor authentication for SSH connections is not supported at this time. +{{< /note >}} + 2. Once you've configured everything, click **Test Connection**. If you didn't save your passwords then Workbench will prompt for them. {{< note >}} diff --git a/docs/development/ci/automate-builds-with-jenkins-on-ubuntu/index.md b/docs/development/ci/automate-builds-with-jenkins-on-ubuntu/index.md index 2a359d72824..be8e3b15cd9 100644 --- a/docs/development/ci/automate-builds-with-jenkins-on-ubuntu/index.md +++ b/docs/development/ci/automate-builds-with-jenkins-on-ubuntu/index.md @@ -17,6 +17,7 @@ title: 'How to Automate Builds with Jenkins on Ubuntu' external_resources: - '[Jenkins User Documentation](https://jenkins.io/doc/)' - '[Blue Ocean Documentation](https://jenkins.io/doc/book/blueocean/)' +audiences: ["intermediate"] --- [Jenkins](https://jenkins.io) is an open-source automation server that allows you to build pipelines to automate the process of building, testing, and deploying applications. In this guide, you will implement a basic workflow to speed up your Continuous Integration and Continuous Delivery (CI/CD) process. diff --git a/docs/development/ci/how-to-develop-and-deploy-your-applications-using-wercker/index.md b/docs/development/ci/how-to-develop-and-deploy-your-applications-using-wercker/index.md index 8bbc16bee70..06912320d3c 100644 --- a/docs/development/ci/how-to-develop-and-deploy-your-applications-using-wercker/index.md +++ b/docs/development/ci/how-to-develop-and-deploy-your-applications-using-wercker/index.md @@ -16,6 +16,7 @@ contributor: name: Damaso Sanoja external_resources: - '[Wercker Developer Documentation](http://devcenter.wercker.com/docs/home)' +audiences: ["intermediate"] --- diff --git a/docs/development/ci/introduction-ci-cd/index.md b/docs/development/ci/introduction-ci-cd/index.md index efaa399a003..571acd298d8 100644 --- a/docs/development/ci/introduction-ci-cd/index.md +++ b/docs/development/ci/introduction-ci-cd/index.md @@ -14,6 +14,7 @@ modified_by: title: Introduction to Continuous Integration/Continuous Delivery (CI/CD) external_resources: - '[How to Automate Builds with Jenkins on Ubuntu](/docs/development/ci/automate-builds-with-jenkins-on-ubuntu/)' +audiences: ["foundational", "beginner"] --- ## What is Continuous Integration? diff --git a/docs/development/ci/use-buildbot-for-software-testing-on-ubuntu/index.md b/docs/development/ci/use-buildbot-for-software-testing-on-ubuntu/index.md index 41e4a20c014..649340246e6 100644 --- a/docs/development/ci/use-buildbot-for-software-testing-on-ubuntu/index.md +++ b/docs/development/ci/use-buildbot-for-software-testing-on-ubuntu/index.md @@ -14,6 +14,7 @@ title: Use Buildbot for Software Testing on Ubuntu 18.04 external_resources: - '[Official Buildbot Tutorial](http://docs.buildbot.net/current/tutorial/)' - '[Buildbot Documentation](http://docs.buildbot.net/current/index.html)' +audiences: ["intermediate"] --- [Buildbot](https://buildbot.net/) is an open source system for testing software projects. In this guide, you will set up a Linode as a Buildbot server to use as a continuous integration platform to test code. Similarly to hosted solutions like Travis CI, Buildbot is an automated testing platform that can watch for code changes, test a project's code, and send notifications regarding build failures. @@ -22,13 +23,13 @@ external_resources: 1. Familiarize yourself with Linode's [Getting Started](/docs/getting-started/) guide and complete the steps for deploying and setting up a Linode running Ubuntu 18.04, including setting the hostname and timezone. -1. This guide uses `sudo` wherever possible. Complete the sections of our [Securing Your Server](/docs/security/securing-your-server/) guide to create a standard user account, harden SSH access and remove unnecessary network services. +2. This guide uses `sudo` wherever possible. Complete the sections of our [Securing Your Server](/docs/security/securing-your-server/) guide to create a standard user account, harden SSH access and remove unnecessary network services. -1. Ensure your system is up to date: +3. Ensure your system is up to date: sudo apt update && sudo apt upgrade -1. Complete the [Add DNS Records](/docs/websites/set-up-web-server-host-website/#add-dns-records) steps to register a domain name that will point to your Linode instance hosting Buildbot. +4. Complete the [Add DNS Records](/docs/websites/set-up-web-server-host-website/#add-dns-records) steps to register a domain name that will point to your Linode instance hosting Buildbot. {{< note >}} Replace each instance of `example.com` in this guide with your Buildbot site's domain name. diff --git a/docs/development/ci/what-is-immutable-infrastructure/index.md b/docs/development/ci/what-is-immutable-infrastructure/index.md index 801e5835f67..049ef633ca5 100644 --- a/docs/development/ci/what-is-immutable-infrastructure/index.md +++ b/docs/development/ci/what-is-immutable-infrastructure/index.md @@ -12,6 +12,7 @@ modified_by: title: "Immutable Infrastructure" contributor: name: Linode +audiences: ["intermediate"] --- ## What is Immutable Infrastructure? diff --git a/docs/development/clojure-deployment-with-immutant-and-wildfly-on-ubuntu-14-04/index.md b/docs/development/clojure-deployment-with-immutant-and-wildfly-on-ubuntu-14-04/index.md index e103ee24430..a34d0d57036 100644 --- a/docs/development/clojure-deployment-with-immutant-and-wildfly-on-ubuntu-14-04/index.md +++ b/docs/development/clojure-deployment-with-immutant-and-wildfly-on-ubuntu-14-04/index.md @@ -20,7 +20,8 @@ external_resources: - '[Luminus Framework](http://www.luminusweb.net/docs)' - '[Immutant 2](http://immutant.org/documentation/current/apidoc/)' - '[Script to install JBoss Wildfly 10.x as service in Linux](https://gist.github.com/sukharevd/6087988)' - +audiences: ["beginner"] +concentrations: ["Web Applications"] --- Clojure is a general-purpose programming language with an emphasis on functional programming. It is a dialect of the Lisp programming language running on the Java Virtual Machine (JVM). While Clojure allows you to write elegant and concise code, its ability to make use of the existing JVM infrastructure, such as libraries, tools and application servers, makes it also a very practical choice. diff --git a/docs/development/frameworks/apache-tomcat-on-ubuntu-16-04/index.md b/docs/development/frameworks/apache-tomcat-on-ubuntu-16-04/index.md index 07f02e9600d..22092a88cf4 100644 --- a/docs/development/frameworks/apache-tomcat-on-ubuntu-16-04/index.md +++ b/docs/development/frameworks/apache-tomcat-on-ubuntu-16-04/index.md @@ -14,6 +14,9 @@ title: 'Install Apache Tomcat on Ubuntu 16.04' external_resources: - '[Tomcat Home Page](http://tomcat.apache.org/)' - '[Tomcat FAQ](http://wiki.apache.org/tomcat/FAQ)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["java"] --- Apache Tomcat is an open-source software implementation of the Java Servlet and Java Server Pages technologies. With this guide, you'll run applications within Tomcat using the OpenJDK implementation of the Java development environment. diff --git a/docs/development/frameworks/yesod-nginx-mysql-on-debian-7-wheezy/index.md b/docs/development/frameworks/yesod-nginx-mysql-on-debian-7-wheezy/index.md index bd34e82af5b..19274eb99b7 100644 --- a/docs/development/frameworks/yesod-nginx-mysql-on-debian-7-wheezy/index.md +++ b/docs/development/frameworks/yesod-nginx-mysql-on-debian-7-wheezy/index.md @@ -18,6 +18,7 @@ external_resources: - '[Haskell Wiki for *cabal-install*](http://www.haskell.org/haskellwiki/Cabal-Install)' - '[Information for *yesod-platform*](http://hackage.haskell.org/package/yesod-platform)' - '[Yesod Quick Start Guide](http://www.yesodweb.com/page/quickstart)' +concentrations: ["Web Applications"] --- diff --git a/docs/development/go/getting-started-with-go-packages/index.md b/docs/development/go/getting-started-with-go-packages/index.md index dd4c8e9b863..fd6613f2855 100644 --- a/docs/development/go/getting-started-with-go-packages/index.md +++ b/docs/development/go/getting-started-with-go-packages/index.md @@ -17,6 +17,8 @@ external_resources: - '[A Tour of Go](https://tour.golang.org/)' - '[The Go Standard Library](https://golang.org/pkg/)' - '[Go Essentials for Full Stack Web Development](https://www.packtpub.com/web-development/go-essentials-full-stack-web-development-video/)' +audiences: ["beginner"] +languages: ["go"] --- ## What is Go? diff --git a/docs/development/go/install-go-on-ubuntu/index.md b/docs/development/go/install-go-on-ubuntu/index.md index 2420a7502a4..8fe24c04f7f 100644 --- a/docs/development/go/install-go-on-ubuntu/index.md +++ b/docs/development/go/install-go-on-ubuntu/index.md @@ -11,6 +11,8 @@ modified: 2018-01-29 modified_by: name: Linode title: 'How to Install Go on Ubuntu' +audiences: ["beginner"] +languages: ["go"] --- ![How to Install Go on Ubuntu](install-go-ubuntu-title.jpg "How to Install Go on Ubuntu") diff --git a/docs/development/introduction-to-websockets/index.md b/docs/development/introduction-to-websockets/index.md index ed0838cba98..2ea5236d3da 100644 --- a/docs/development/introduction-to-websockets/index.md +++ b/docs/development/introduction-to-websockets/index.md @@ -18,6 +18,7 @@ external_resources: - '[Vanessa Wang, *The Definitive Guide to HTML5 WebSocket*](https://www.apress.com/in/book/9781430247401)' - '[About HTML5 WebSocket](https://www.websocket.org/aboutwebsocket.html)' - '[The WebSocket Protocol](https://tools.ietf.org/html/rfc6455)' +audiences: ["beginner"] --- ## What are WebSockets? diff --git a/docs/development/iot/install-thingsboard-iot-dashboard/index.md b/docs/development/iot/install-thingsboard-iot-dashboard/index.md index 8b1310fa9dc..06899e1a6a5 100644 --- a/docs/development/iot/install-thingsboard-iot-dashboard/index.md +++ b/docs/development/iot/install-thingsboard-iot-dashboard/index.md @@ -14,6 +14,7 @@ title: 'View IoT Data with ThingsBoard' external_resources: - '[Getting Started – ThingsBoard](https://thingsboard.io/docs/getting-started-guides/helloworld)' - '[ThingsBoard Github Repo](https://github.com/thingsboard/thingsboard)' +audiences: ["intermediate"] --- ![View IoT Data with ThingsBoard](ThingsBoard.jpg) diff --git a/docs/development/java/how-to-deploy-spring-boot-applications-nginx-ubuntu-16-04/index.md b/docs/development/java/how-to-deploy-spring-boot-applications-nginx-ubuntu-16-04/index.md index 668d4a9ca15..42a82924da0 100644 --- a/docs/development/java/how-to-deploy-spring-boot-applications-nginx-ubuntu-16-04/index.md +++ b/docs/development/java/how-to-deploy-spring-boot-applications-nginx-ubuntu-16-04/index.md @@ -16,6 +16,9 @@ external_resources: - '[Spring Boot](https://projects.spring.io/spring-boot/)' - '[SDKMAN!](http://sdkman.io/)' - '[Gradle](https://gradle.org/)' +audiences: ["intermediate"] +concentrations: ["Web Applications"] +languages: ["java"] --- ![How to Deploy Spring Boot Applications on NGINX on Ubuntu 16.04](deploy-spring-boot-nginx-reverse-proxy.jpg "How to Deploy Spring Boot Applications on NGINX on Ubuntu 16.04") diff --git a/docs/development/java/install-java-on-centos/index.md b/docs/development/java/install-java-on-centos/index.md index 38babb8ab41..0734be966cc 100644 --- a/docs/development/java/install-java-on-centos/index.md +++ b/docs/development/java/install-java-on-centos/index.md @@ -13,6 +13,8 @@ published: 2017-06-01 title: Install Java on Centos 7 external_resources: - '[Fedora Wiki Java Entry](https://fedoraproject.org/wiki/Java)' +audiences: ["beginner"] +languages: ["java"] --- ![Install Java on CentOS 7](install-java-on-centos-7-title-graphic.jpg "Install Java on CentOS 7") diff --git a/docs/development/java/install-java-on-debian/index.md b/docs/development/java/install-java-on-debian/index.md index b8158ba7a61..a70e96c556d 100644 --- a/docs/development/java/install-java-on-debian/index.md +++ b/docs/development/java/install-java-on-debian/index.md @@ -13,6 +13,8 @@ published: 2017-06-01 title: Install Java on Debian 8 external_resources: - '[Java Debian Wiki](https://wiki.debian.org/Java)' +audiences: ["beginner"] +languages: ["java"] --- Java is a powerful programming language. Software written in Java can be compiled and run on any system. Unlike Python or C, Java does not come pre-installed on Linode distribution images. This guide installs the OpenJDK 7 runtime environment and development kit in Debian 8. OpenJDK is the free and open-source implementation of the Java SE Development Kit. diff --git a/docs/development/java/install-java-on-ubuntu-16-04/index.md b/docs/development/java/install-java-on-ubuntu-16-04/index.md index b0cebe0882b..beb49fe8789 100644 --- a/docs/development/java/install-java-on-ubuntu-16-04/index.md +++ b/docs/development/java/install-java-on-ubuntu-16-04/index.md @@ -16,7 +16,9 @@ contributor: link: https://github.com/pbzona external_resources: - '[Oracle Java](https://www.oracle.com/java/index.html)' +audiences: ["beginner"] +languages: ["java"] --- ![Java](Install_Oracle_Java.jpg) diff --git a/docs/development/java/install-java-on-ubuntu-18-04/index.md b/docs/development/java/install-java-on-ubuntu-18-04/index.md index be08f432ff6..5521a7688b6 100644 --- a/docs/development/java/install-java-on-ubuntu-18-04/index.md +++ b/docs/development/java/install-java-on-ubuntu-18-04/index.md @@ -23,6 +23,8 @@ contributor: link: 'https://github.com/pbzona' external_resources: - '[Oracle Java](https://www.oracle.com/java/index.html)' +audiences: ["beginner"] +languages: ["java"] --- [Java](https://www.oracle.com/java/index.html) is one of the world's most popular programming languages. Java can be used to create anything from software to basic web applications. diff --git a/docs/development/java/java-development-wildfly-centos-7/index.md b/docs/development/java/java-development-wildfly-centos-7/index.md index e887cac3f00..0dcf6876772 100644 --- a/docs/development/java/java-development-wildfly-centos-7/index.md +++ b/docs/development/java/java-development-wildfly-centos-7/index.md @@ -16,6 +16,9 @@ contributor: link: https://github.com/ashraffouad external_resources: - '[WildFly Administration Guide](https://books.google.com.sa/books?id=rufiBAAAQBAJ)' +audiences: ["intermediate"] +concentrations: ["Web Applications"] +languages: ["java"] --- ![Java Development with WildFly on CentOS 7](Java-Development-with-WildFly-on-CentOS-7-smg.jpg) diff --git a/docs/development/javascript/deploy-a-react-app-on-linode/index.md b/docs/development/javascript/deploy-a-react-app-on-linode/index.md index 07b7c6cd96d..8bebc0f9a6d 100644 --- a/docs/development/javascript/deploy-a-react-app-on-linode/index.md +++ b/docs/development/javascript/deploy-a-react-app-on-linode/index.md @@ -17,6 +17,9 @@ contributor: external_resources: - '[React - A JavaScript library for building user interfaces](https://reactjs.org/)' - '[Deploy a React App with Sass Using NGINX](http://zabana.me/notes/build-deploy-react-app-with-nginx.html)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["javascript"] --- ## What is React? diff --git a/docs/development/julia/why-learn-julia/Why_You_Should_Learn_Julia_smg.jpg b/docs/development/julia/why-learn-julia/Why_You_Should_Learn_Julia_smg.jpg new file mode 100644 index 00000000000..fd24ab9650f Binary files /dev/null and b/docs/development/julia/why-learn-julia/Why_You_Should_Learn_Julia_smg.jpg differ diff --git a/docs/development/julia/why-learn-julia/index.md b/docs/development/julia/why-learn-julia/index.md index 5f43b65e1e8..6a48c9e49a7 100644 --- a/docs/development/julia/why-learn-julia/index.md +++ b/docs/development/julia/why-learn-julia/index.md @@ -5,7 +5,7 @@ author: description: Julia is a dynamically typed, functional programming language intended to match the readable syntax and ease of use of Python without sacrificing the performance of a traditional compiled language. This guide introduces the main features, benefits, and limitations of Julia and includes a brief section on installation and basic use. keywords: ['data science','julia','python','why learn Julia'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -published: 2018-06-11 +published: 2018-12-11 modified: 2018-06-11 modified_by: name: Linode @@ -14,7 +14,11 @@ external_resources: - '[Julia](https://julialang.org/)' - '[Julia By Example](https://juliabyexample.helpmanual.io/)' - '[JuliaBox](https://juliabox.com/)' +audiences: ["beginner"] +concentrations: ["Scientific Computing and Big Data"] +languages: ["julia"] --- +![Why You Should Learn Julia](Why_You_Should_Learn_Julia_smg.jpg) ## What is Julia? diff --git a/docs/development/monitor-filesystem-events-with-pyinotify/index.md b/docs/development/monitor-filesystem-events-with-pyinotify/index.md index c9cb9165114..7f566dda619 100644 --- a/docs/development/monitor-filesystem-events-with-pyinotify/index.md +++ b/docs/development/monitor-filesystem-events-with-pyinotify/index.md @@ -17,6 +17,8 @@ external_resources: - '[Pyinotify on Github](https://github.com/seb-m/pyinotify)' - '[Pyinotify API documentation](http://seb-m.github.com/pyinotify)' - '[Inotify manpage](http://www.kernel.org/doc/man-pages/online/pages/man7/inotify.7.html)' +audiences: ["intermediate"] +languages: ["python"] --- ![banner_image](Monitor_Filesystem_Events_with_Pyinotify_smg.jpg) diff --git a/docs/development/nodejs/how-to-install-nodejs-and-nginx-on-debian/index.md b/docs/development/nodejs/how-to-install-nodejs-and-nginx-on-debian/index.md index db2dae49223..15090fc4a6c 100644 --- a/docs/development/nodejs/how-to-install-nodejs-and-nginx-on-debian/index.md +++ b/docs/development/nodejs/how-to-install-nodejs-and-nginx-on-debian/index.md @@ -19,6 +19,9 @@ external_resources: - '[NodeSchool](http://nodeschool.io/)' - '[Node Version Manager](https://github.com/creationix/nvm)' - '[npm](https://www.npmjs.com/)' +audiences: ["intermediate"] +concentrations: ["Web Applications"] +languages: ["javascript"] --- ![Install Node.js and NGINX on Debian](How_to_Install_Nodejs_and_Nginx_on_Debian_smg.jpg) diff --git a/docs/development/nodejs/how-to-install-nodejs/index.md b/docs/development/nodejs/how-to-install-nodejs/index.md index 30aa3c88ea1..3107371c9d7 100644 --- a/docs/development/nodejs/how-to-install-nodejs/index.md +++ b/docs/development/nodejs/how-to-install-nodejs/index.md @@ -15,6 +15,8 @@ external_resources: - '[NodeSchool](http://nodeschool.io/)' - '[Node Version Manager](https://github.com/creationix/nvm)' - '[npm](https://www.npmjs.com/)' +audiences: ["beginner"] +languages: ["javascript"] --- [Node.js](https://nodejs.org/) is a cross-platform runtime environment for server-side JavaScript applications. Node.js uses [V8](https://developers.google.com/v8/), Google's JavaScript engine, which is also found in Chromium and Chrome. Depending on the use case, Node.js can supplement or replace traditional web servers and tools such as Apache, nginx, or PHP. diff --git a/docs/development/nodejs/install-configure-selenium-grid-ubuntu-16-04/index.md b/docs/development/nodejs/install-configure-selenium-grid-ubuntu-16-04/index.md index 0ee644870d4..66509ccb448 100644 --- a/docs/development/nodejs/install-configure-selenium-grid-ubuntu-16-04/index.md +++ b/docs/development/nodejs/install-configure-selenium-grid-ubuntu-16-04/index.md @@ -15,6 +15,7 @@ h1_title: 'Use Selenium Grid for Cross-Browser Compatibility Testing' external_resources: - '[Selenium Project Home](https://www.seleniumhq.org/projects/webdriver/)' - '[Selenium Node.js Documentation](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index.html)' +audiences: ["intermediate"] --- ## What is Selenium Grid? diff --git a/docs/development/nodejs/use-nightmarejs-to-automate-headless-browsing/index.md b/docs/development/nodejs/use-nightmarejs-to-automate-headless-browsing/index.md index dc9e57996e9..10a42093138 100644 --- a/docs/development/nodejs/use-nightmarejs-to-automate-headless-browsing/index.md +++ b/docs/development/nodejs/use-nightmarejs-to-automate-headless-browsing/index.md @@ -17,6 +17,9 @@ contributor: external_resources: - '[Nightmare.js Homepage](http://www.nightmarejs.org/)' - '[Nightmare.js Github Repository](https://github.com/segmentio/nightmare)' +audiences: ["intermediate"] +concentrations: ["Scripting, Automation, and Build Tools"] +languages: ["javascript"] --- ![Use Nightmare.js to Automate Headless Browsing](nightmarejs-automate-headless-browsing-title.jpg "Use Nightmare.js to Automate Headless Browsing") diff --git a/docs/development/perl/manage-cpan-modules-with-cpan-minus/index.md b/docs/development/perl/manage-cpan-modules-with-cpan-minus/index.md index 6d6a46d0a3d..af9f3a9823c 100644 --- a/docs/development/perl/manage-cpan-modules-with-cpan-minus/index.md +++ b/docs/development/perl/manage-cpan-modules-with-cpan-minus/index.md @@ -15,6 +15,8 @@ title: Manage CPAN Modules with cpanminus external_resources: - '[cpanminus Documentation](http://search.cpan.org/~miyagawa/App-cpanminus-0.9929/lib/App/cpanminus.pm)' - '[cpanminus Development](http://github.com/miyagawa/cpanminus/)' +audiences: ["beginner"] +languages: ["perl"] --- ![banner_image](Manage_CPAN_Modules_with_cpanminus_smg.jpg) diff --git a/docs/development/python/create-a-python-virtualenv-on-ubuntu-1610/index.md b/docs/development/python/create-a-python-virtualenv-on-ubuntu-1610/index.md index 69bcd1fc19d..ae6ec462760 100644 --- a/docs/development/python/create-a-python-virtualenv-on-ubuntu-1610/index.md +++ b/docs/development/python/create-a-python-virtualenv-on-ubuntu-1610/index.md @@ -17,6 +17,8 @@ contributor: link: https://twitter.com/chrispiccini11 external_resources: - '[virtualenv Documentation](http://virtualenv.pypa.io/)' +audiences: ["beginner"] +languages: ["python"] --- ![Create a Python Virtual Environment on Ubuntu 16.10](python-ve-u16-title.jpg "Create a Python Virtual Environment on Ubuntu 16.10") diff --git a/docs/development/python/introduction-to-pyspark/index.md b/docs/development/python/introduction-to-pyspark/index.md index 349642a0cc5..0ebc125f661 100644 --- a/docs/development/python/introduction-to-pyspark/index.md +++ b/docs/development/python/introduction-to-pyspark/index.md @@ -15,6 +15,9 @@ external_resources: - '[AMPLab Paper on RDDs](https://www.usenix.org/system/files/conference/nsdi12/nsdi12-final138.pdf)' - '[Spark Documentation](https://spark.apache.org/)' - '[PySpark Documentation](https://spark.apache.org/docs/latest/api/python/#)' +audiences: ["intermediate"] +concentrations: ["Scientific Computing and Big Data"] +languages: ["python"] --- ![Introduction to PySpark](PySpark.jpg) diff --git a/docs/development/python/manage-python-environments-pipenv/index.md b/docs/development/python/manage-python-environments-pipenv/index.md index a7adb31eec4..b9669d84d2b 100644 --- a/docs/development/python/manage-python-environments-pipenv/index.md +++ b/docs/development/python/manage-python-environments-pipenv/index.md @@ -11,6 +11,8 @@ modified_by: name: Linode published: 2018-05-01 title: Manage Python Packages and Virtual Environments with Pipenv +audiences: ["beginner"] +languages: ["python"] --- ## What is Pipenv? diff --git a/docs/development/python/string-manipulation-python-3/index.md b/docs/development/python/string-manipulation-python-3/index.md index d0fcfd69695..150053b3fc6 100644 --- a/docs/development/python/string-manipulation-python-3/index.md +++ b/docs/development/python/string-manipulation-python-3/index.md @@ -13,6 +13,9 @@ modified_by: title: 'String Manipulation in Python 3' external_resources: - '[Official f-strings Documentation](https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings)' +audiences: ["beginner"] +concentrations: ["Scripting, Automation, and Build Tools"] +languages: ["python"] --- ## Strings in Python diff --git a/docs/development/python/task-queue-celery-rabbitmq/index.md b/docs/development/python/task-queue-celery-rabbitmq/index.md index 0f8c37f93af..85ffba0d43f 100644 --- a/docs/development/python/task-queue-celery-rabbitmq/index.md +++ b/docs/development/python/task-queue-celery-rabbitmq/index.md @@ -15,6 +15,9 @@ contributor: external_resources: - '[Celery Project page](http://www.celeryproject.org/)' - '[Official Celery Documentation](http://docs.celeryproject.org/en/latest/index.html)' +audiences: ["intermediate"] +concentrations: ["Scripting, Automation, and Build Tools"] +languages: ["python"] --- ![How to Set Up a Task Queue with Celery and RabbitMQ](how-to-set-up-a-task-queue-with-celery-and-rabbitmq-smg.jpg) diff --git a/docs/development/python/use-scrapy-to-extract-data-from-html-tags/index.md b/docs/development/python/use-scrapy-to-extract-data-from-html-tags/index.md index 36eed68afbf..e435b82973a 100644 --- a/docs/development/python/use-scrapy-to-extract-data-from-html-tags/index.md +++ b/docs/development/python/use-scrapy-to-extract-data-from-html-tags/index.md @@ -15,6 +15,9 @@ contributor: external_resources: - '[Scrapy Project page](https://scrapy.org/)' - '[Official Scrapy Documentation](https://doc.scrapy.org/en/latest/index.html)' +audiences: ["intermediate"] +concentrations: ["Scripting, Automation, and Build Tools"] +languages: ["python"] --- ![Use Scrapy to Extract Data from HTML Tags](Use-Scrapy-to-Extract-Data-From-HTML-Tags-smg.jpg) diff --git a/docs/development/r/how-to-deploy-rshiny-server-on-ubuntu-and-debian/index.md b/docs/development/r/how-to-deploy-rshiny-server-on-ubuntu-and-debian/index.md index 062f0b6c899..2c35b938de6 100644 --- a/docs/development/r/how-to-deploy-rshiny-server-on-ubuntu-and-debian/index.md +++ b/docs/development/r/how-to-deploy-rshiny-server-on-ubuntu-and-debian/index.md @@ -14,6 +14,9 @@ title: 'How to Deploy Interactive R Apps with Shiny Server' external_resources: - '[Shiny Server – Introduction](https://shiny.rstudio.com/articles/shiny-server.html)' - '[Gallery of Shiny Apps](https://shiny.rstudio.com/gallery/)' +audiences: ["beginner"] +concentrations: ["Scientific Computing and Big Data"] +languages: ["r"] --- ![How to Deploy Interactive R Apps with Shiny Server](shiny-server.jpg) diff --git a/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/How_to_Deploy_RStudio_Server_Using_an_NGINX_Reverse_Proxy_smg.jpg b/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/How_to_Deploy_RStudio_Server_Using_an_NGINX_Reverse_Proxy_smg.jpg new file mode 100644 index 00000000000..829b23bb409 Binary files /dev/null and b/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/How_to_Deploy_RStudio_Server_Using_an_NGINX_Reverse_Proxy_smg.jpg differ diff --git a/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/index.md b/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/index.md index c7917372697..8e62a61c281 100644 --- a/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/index.md +++ b/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/index.md @@ -6,13 +6,18 @@ description: 'RStudio Server is a the web based version of RStudio for a desktop og_description: 'RStudio Server is a the web based version of RStudio for a desktop environment. Gain access to your R development environment from anywhere in the world.' keywords: ['R', 'statistic', 'R Foundation', 'data visualization'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2018-01-29 +modified: 2019-12-11 modified_by: name: Linode published: 2018-01-29 title: 'How to Deploy RStudio Server Using an NGINX Reverse Proxy' +audiences: ["beginner"] +concentrations: ["Scientific Computing and Big Data"] +languages: ["r"] --- +![How to Deploy Rstudio using an NGINX reverse proxy](How_to_Deploy_RStudio_Server_Using_an_NGINX_Reverse_Proxy_smg.jpg) + ## What is RStudio Server? [RStudio](https://www.rstudio.com) is an integrated development environment (IDE) for [R](https://www.r-project.org/), an open source statistical computing language. It includes debugging and plotting tools that make it easy to write, debug, and run R scripts. The IDE is available in both desktop and server configurations. By hosting the server configuration (RStudio Server) on a Linode, you can access the IDE from any computer with internet access. Since data analysis often uses large datasets and can be computationally expensive, keeping your data and running R scripts from a remote server can be more efficient than working from your personal computer. In addition, a professional edition is available that allows project sharing and simultaneous code editing for multiple users. diff --git a/docs/development/r/how-to-install-r-on-ubuntu-and-debian/index.md b/docs/development/r/how-to-install-r-on-ubuntu-and-debian/index.md index 8d7bbbf5f59..35b42b5a4a8 100644 --- a/docs/development/r/how-to-install-r-on-ubuntu-and-debian/index.md +++ b/docs/development/r/how-to-install-r-on-ubuntu-and-debian/index.md @@ -11,6 +11,9 @@ modified_by: name: Linode published: 2018-01-29 title: 'How to install R on Ubuntu and Debian' +audiences: ["beginner"] +concentrations: ["Scientific Computing and Big Data"] +languages: ["r"] --- ![How to install R on Ubuntu and Debian](install-r-ubuntu-debian-title.jpg "How to install R on Ubuntu and Debian title graphic") diff --git a/docs/development/ror/ruby-on-rails-apache-debian-8/index.md b/docs/development/ror/ruby-on-rails-apache-debian-8/index.md index 9c01a878584..05f9b59ee40 100644 --- a/docs/development/ror/ruby-on-rails-apache-debian-8/index.md +++ b/docs/development/ror/ruby-on-rails-apache-debian-8/index.md @@ -17,6 +17,9 @@ og_description: 'This tutorial will teach you how to use an Apache web server wi external_resources: - '[Ruby on Rails Homepage](http://rubyonrails.org/)' - '[mod_rails Documentation for Apache Servers](http://www.modrails.com/documentation/Users%20guide%20Apache.html)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["ruby"] --- Ruby on Rails is a rapid development web framework that allows web designers and developers to implement dynamic fully featured web applications. This guide deploys Rails applications using the Phusion Passenger or `mod_rails` method. Passenger allows you to embed Rails apps directly in Apache applications without needing to worry about FastCGI or complex web server proxies. diff --git a/docs/development/ror/ruby-on-rails-apache-debian/index.md b/docs/development/ror/ruby-on-rails-apache-debian/index.md index f664a5e0946..adb9b05ad59 100644 --- a/docs/development/ror/ruby-on-rails-apache-debian/index.md +++ b/docs/development/ror/ruby-on-rails-apache-debian/index.md @@ -15,6 +15,9 @@ title: 'Install Ruby on Rails with Apache on Debian 9' external_resources: - '[Ruby on Rails Homepage](http://rubyonrails.org/)' - '[Phusion Passenger](https://www.phusionpassenger.com/)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["ruby"] --- ![Ruby on Rails with Apache on Debian](ruby_on_rails_with_apache_debian.jpg "Ruby on Rails with Apache on Debian") diff --git a/docs/development/ror/ruby-on-rails-nginx-debian/index.md b/docs/development/ror/ruby-on-rails-nginx-debian/index.md index ca3305d7590..5bad0afe00f 100644 --- a/docs/development/ror/ruby-on-rails-nginx-debian/index.md +++ b/docs/development/ror/ruby-on-rails-nginx-debian/index.md @@ -20,6 +20,9 @@ external_resources: - '[NGINX Home Page](http://nginx.org/)' - '[NGINX Documentation](http://nginx.org/en/docs/)' - '[NGINX Configuration](/docs/websites/nginx/basic-nginx-configuration)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["ruby"] --- ![Ruby on Rails with nginx on Debian](ruby_on_rails_with_nginx_debian_8_smg.png "Ruby on Rails with nginx on Debian 8") diff --git a/docs/development/ror/ruby-on-rails-with-nginx-on-debian-7-wheezy/index.md b/docs/development/ror/ruby-on-rails-with-nginx-on-debian-7-wheezy/index.md index 0a72a3450ad..1434c6b31fa 100644 --- a/docs/development/ror/ruby-on-rails-with-nginx-on-debian-7-wheezy/index.md +++ b/docs/development/ror/ruby-on-rails-with-nginx-on-debian-7-wheezy/index.md @@ -17,6 +17,9 @@ external_resources: - '[Nginx Home Page](http://nginx.org/)' - '[Nginx Documentation](http://nginx.org/en/docs/)' - '[Nginx Configuration](/docs/websites/nginx/basic-nginx-configuration)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["ruby"] --- Ruby on Rails is a popular rapid development web framework that allows web designers and developers to implement fully featured dynamic web applications using the Ruby programming language. This guide describes the required process for deploying Ruby on Rails with Passenger and the Nginx web server on Debian 7 (Wheezy). For the purposes of this tutorial, it is assumed that you've followed the steps outlined in our [getting started guide](/docs/getting-started/), that your system is up to date, and that you've logged into your Linode as root via SSH. diff --git a/docs/development/ror/use-unicorn-and-nginx-on-ubuntu-14-04/index.md b/docs/development/ror/use-unicorn-and-nginx-on-ubuntu-14-04/index.md index d47f0af3f5c..b5991df5735 100644 --- a/docs/development/ror/use-unicorn-and-nginx-on-ubuntu-14-04/index.md +++ b/docs/development/ror/use-unicorn-and-nginx-on-ubuntu-14-04/index.md @@ -16,6 +16,9 @@ contributor: link: https://twitter.com/rootaux external_resources: - '[Ruby on Rails](http://rubyonrails.org/)' +audiences: ["beginner"] +concentrations: ["Web Applications"] +languages: ["ruby"] --- Ruby on Rails is a popular web-application framework that allows developers to create dynamic web applications. This guide describes how to deploy Rails applications on servers using Unicorn and nginx on Ubuntu 14.04. diff --git a/docs/development/use-a-linode-for-web-development-on-remote-devices/index.md b/docs/development/use-a-linode-for-web-development-on-remote-devices/index.md index ea54b7e3af0..83ff7e60c14 100644 --- a/docs/development/use-a-linode-for-web-development-on-remote-devices/index.md +++ b/docs/development/use-a-linode-for-web-development-on-remote-devices/index.md @@ -17,6 +17,7 @@ title: 'Use a Linode for Web Development on Remote Devices' external_resources: - '[Docker Docs](http://docs.docker.com/)' - '[Portainer](https://portainer.io/)' +audiences: ["beginner"] --- ![Use a Linode for Web Development on Remote Devices](Linode_WebDev.jpg "WebDev_Title Graphic") diff --git a/docs/development/version-control/how-to-configure-git/index.md b/docs/development/version-control/how-to-configure-git/index.md index a45656533b3..752e201bb5e 100644 --- a/docs/development/version-control/how-to-configure-git/index.md +++ b/docs/development/version-control/how-to-configure-git/index.md @@ -15,6 +15,7 @@ external_resources: - '[Learn Git with Bitbucket Cloud](https://www.atlassian.com/git/tutorials/learn-git-with-bitbucket-cloud)' - '[Pro Git Book](https://git-scm.com/book/en/v2)' - '[Github Guides](https://guides.github.com/)' +audiences: ["foundational"] --- ![Git Started Today](git_getting_started.png) diff --git a/docs/development/version-control/how-to-install-git-and-clone-a-github-repository/index.md b/docs/development/version-control/how-to-install-git-and-clone-a-github-repository/index.md index 82720a28153..41554f70d49 100644 --- a/docs/development/version-control/how-to-install-git-and-clone-a-github-repository/index.md +++ b/docs/development/version-control/how-to-install-git-and-clone-a-github-repository/index.md @@ -14,6 +14,7 @@ modified_by: name: Linode published: 2015-02-06 title: How to Install Git and Clone a GitHub Repository +audiences: ["beginner"] --- ![How to Install Git and Clone a GitHub Repository](install-clone-github-repo-title.jpg "How to Install Git and Clone a GitHub Repository title graphic") diff --git a/docs/development/version-control/how-to-install-git-on-linux-mac-and-windows/index.md b/docs/development/version-control/how-to-install-git-on-linux-mac-and-windows/index.md index 5a88d3746cb..4722e0cb054 100644 --- a/docs/development/version-control/how-to-install-git-on-linux-mac-and-windows/index.md +++ b/docs/development/version-control/how-to-install-git-on-linux-mac-and-windows/index.md @@ -17,6 +17,7 @@ external_resources: - '[Learn Git with Bitbucket Cloud](https://www.atlassian.com/git/tutorials/learn-git-with-bitbucket-cloud)' - '[Pro Git Book](https://git-scm.com/book/en/v2)' - '[Github Guides](https://guides.github.com/)' +audiences: ["foundational"] --- ## Introduction to Git diff --git a/docs/development/version-control/how-to-unbundle-nginx-from-omnibus-gitlab-for-serving-multiple-websites/index.md b/docs/development/version-control/how-to-unbundle-nginx-from-omnibus-gitlab-for-serving-multiple-websites/index.md index a521da4b255..029fd0084fb 100644 --- a/docs/development/version-control/how-to-unbundle-nginx-from-omnibus-gitlab-for-serving-multiple-websites/index.md +++ b/docs/development/version-control/how-to-unbundle-nginx-from-omnibus-gitlab-for-serving-multiple-websites/index.md @@ -17,6 +17,7 @@ title: 'How to Unbundle nginx from Omnibus GitLab for Serving Multiple Websites' external_resources: - '[Updating GitLab via Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md)' - '[Installing Passenger + nginx](https://www.phusionpassenger.com/library/install/nginx/install/oss/trusty/)' +audiences: ["intermediate"] --- diff --git a/docs/development/version-control/install-gitlab-on-ubuntu-14-04-trusty-tahr/index.md b/docs/development/version-control/install-gitlab-on-ubuntu-14-04-trusty-tahr/index.md index b05694668e1..2e2cc9b808b 100644 --- a/docs/development/version-control/install-gitlab-on-ubuntu-14-04-trusty-tahr/index.md +++ b/docs/development/version-control/install-gitlab-on-ubuntu-14-04-trusty-tahr/index.md @@ -19,6 +19,7 @@ external_resources: - '[GitLab Documentation](https://www.gitlab.com/documentation/)' - '[GitLab Requirements](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/requirements.md)' - '[GitLab Manual Installation](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md)' +audiences: ["intermediate"] --- diff --git a/docs/development/version-control/install-gogs-on-debian/index.md b/docs/development/version-control/install-gogs-on-debian/index.md index 4cd636f926c..8458c6e483c 100644 --- a/docs/development/version-control/install-gogs-on-debian/index.md +++ b/docs/development/version-control/install-gogs-on-debian/index.md @@ -18,6 +18,7 @@ external_resources: - '[Gogs official site](http://gogs.io)' - '[Gogs documentation](http://gogs.io/docs)' - '[Gogs: GitLab alternative in Go](http://blog.gopheracademy.com/birthday-bash-2014/gogs-gitlab-alternative-in-go/)' +audiences: ["intermediate"] --- diff --git a/docs/development/version-control/introduction-to-version-control/index.md b/docs/development/version-control/introduction-to-version-control/index.md index 1eb7315cac2..bc095837f2f 100644 --- a/docs/development/version-control/introduction-to-version-control/index.md +++ b/docs/development/version-control/introduction-to-version-control/index.md @@ -13,6 +13,7 @@ published: 2013-09-18 title: Introduction to Version Control external_resources: - '[Version Control Systems](/docs/development/version-control/)' +audiences: ["foundational"] --- In the [Hosting a Website](/docs/websites/hosting-a-website/) guide, you learned how to host your website by installing and configuring a web server, database, and PHP. Now it's time to implement version control to protect your data and handle code updates smoothly. By the time you reach the end of this guide, you'll know how to use many of the version control methods and tools used by large organizations. diff --git a/docs/development/version-control/manage-distributed-version-control-with-mercurial/index.md b/docs/development/version-control/manage-distributed-version-control-with-mercurial/index.md index b7b0f7a4d11..fce0cd423d1 100644 --- a/docs/development/version-control/manage-distributed-version-control-with-mercurial/index.md +++ b/docs/development/version-control/manage-distributed-version-control-with-mercurial/index.md @@ -13,6 +13,7 @@ published: 2010-04-26 title: Manage Distributed Version Control with Mercurial external_resources: - '[HG Init, a Guide by Joel Spolsky](http://hginit.com/)' +audiences: ["beginner"] --- [Mercurial](https://www.mercurial-scm.org/) is one of the leading distributed version control systems which allows software developers and teams of collaborators to work on a common code base without the need to rely on a centralized server or constant network connection. Mercurial runs on multiple platforms and can be used to manage code projects on many different operating systems. diff --git a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-8/index.md b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-8/index.md index 397ef61fb73..60dd4e9ed90 100644 --- a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-8/index.md +++ b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-8/index.md @@ -5,7 +5,7 @@ author: description: 'Configure SPF and DKIM in Postfix on Debian 8.' keywords: ["email", "postfix", "spf", "dkim", "debian 8", "opendkim", "dns", "dmarc"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2017-03-27 +modified: 2018-12-14 modified_by: name: Linode published: 2016-02-03 @@ -22,6 +22,10 @@ external_resources: - '[DMARC Record Assistant](http://kitterman.com/dmarc/assistant.html) provides a web form to generate a DMARC record for you based on your selections.' --- +{{< note >}} +We have created a [new version of this guide](/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9) to run on Debian 9. +{{< /note >}} + ![SPF and DKIM with Postfix](Configure_SPF_and_DKIM_with_Postfix_on_Debian_8_smg.jpg) [SPF (Sender Policy Framework)](http://www.openspf.org/) is a system that identifies to mail servers what hosts are allowed to send email for a given domain. Setting up SPF helps to prevent your email from being classified as spam. @@ -356,8 +360,8 @@ SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock" milter_default_action = accept # Postfix ≥ 2.6 milter_protocol = 6, Postfix ≤ 2.5 milter_protocol = 2 milter_protocol = 6 -smtpd_milters = local:/opendkim/opendkim.sock -non_smtpd_milters = local:/opendkim/opendkim.sock +smtpd_milters = local:opendkim/opendkim.sock +non_smtpd_milters = local:opendkim/opendkim.sock {{< /file >}} diff --git a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/adsp-record.png b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/adsp-record.png new file mode 100644 index 00000000000..a8c95eb35ec Binary files /dev/null and b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/adsp-record.png differ diff --git a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/dkim-record.png b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/dkim-record.png new file mode 100644 index 00000000000..07a7de364ec Binary files /dev/null and b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/dkim-record.png differ diff --git a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/dmarc-record.png b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/dmarc-record.png new file mode 100644 index 00000000000..75a07de3990 Binary files /dev/null and b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/dmarc-record.png differ diff --git a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/index.md b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/index.md new file mode 100644 index 00000000000..dc2cf835e86 --- /dev/null +++ b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/index.md @@ -0,0 +1,463 @@ +--- +author: + name: Linode Community + email: contribute@linode.com +description: 'Configure SPF and DKIM in Postfix on Debian 9.' +keywords: ["email", "postfix", "spf", "dkim", "debian 9", "opendkim", "dns", "dmarc"] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +modified: 2018-12-13 +modified_by: + name: Linode +published: 2018-12-13 +title: 'Configure SPF and DKIM With Postfix on Debian 9' +contributor: + name: Linode +external_resources: + - '[Sender Policy Framework](http://www.openspf.org/)' + - '[DomainKeys Identified Mail](http://www.dkim.org/)' + - '[DMARC](http://dmarc.org/)' + - '[OpenDKIM](http://www.opendkim.org/)' + - 'The [Sender Policy Framework](https://en.wikipedia.org/wiki/Sender_Policy_Framework) and [DomainKeys Identified Mail](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail) Wikipedia pages should not be considered authoritative but do provide helpful discussion and additional references.' + - '[DMARC Record Assistant](http://kitterman.com/dmarc/assistant.html) provides a web form to generate a DMARC record for you based on your selections.' +--- + +This guide will instruct you on how to set up SPF and DKIM with Postfix. + +[SPF (Sender Policy Framework)](http://www.openspf.org/) is a system that identifies to mail servers what hosts are allowed to send email for a given domain. Setting up SPF helps to prevent your email from being classified as spam. + +[DKIM (DomainKeys Identified Mail)](http://www.dkim.org/) is a system that lets your official mail servers add a signature to headers of outgoing email and identifies your domain's public key so other mail servers can verify the signature. As with SPF, DKIM helps keep your mail from being considered spam. It also lets mail servers detect when your mail has been tampered with in transit. + +[DMARC (Domain Message Authentication, Reporting & Conformance)](http://dmarc.org/) allows you to advertise to mail servers what your domain's policies are regarding mail that fails SPF and/or DKIM validations. It additionally allows you to request reports on failed messages from receiving mail servers. + +The DNS instructions for setting up SPF, DKIM and DMARC are generic. The instructions for configuring the SPF policy agent and OpenDKIM into Postfix should work on any distribution after making respective code adjustments for the package tool, and identifying the exact path to the Unix socket file. + +{{< note >}} +The steps required in this guide require root privileges. Be sure to run the steps below as **root** or with the `sudo` prefix. For more information on privileges see our [Users and Groups](/docs/tools-reference/linux-users-and-groups) guide. +{{< /note >}} + +{{< caution >}} +You must already have Postfix installed, configured and working. Refer to the [Linode Postfix Guides](/docs/email/postfix/) for assistance. + +Publishing an SPF DNS record without having the SPF policy agent configured within Postfix is safe; however, publishing DKIM DNS records without having OpenDKIM working correctly within Postfix can result in your email being discarded by the recipient's email server. +{{< /caution >}} + +## Install DKIM, SPF and Postfix + +1. Install the four required packages: + + apt-get install opendkim opendkim-tools postfix-policyd-spf-python postfix-pcre + +2. Add user `postfix` to the `opendkim` group so that Postfix can access OpenDKIM's socket when it needs to: + + adduser postfix opendkim + +## Set up SPF + +### Add SPF records to DNS + +The value in an SPF DNS record will look something like the following examples. The full syntax is at [the SPF record syntax page](http://www.openspf.org/SPF_Record_Syntax). + +**Example 1** Allow mail from all hosts listed in the MX records for the domain: + + v=spf1 mx -all + +**Example 2** Allow mail from a specific host: + + v=spf1 a:mail.example.com -all + +- The `v=spf1` tag is required and has to be the first tag. + +- The last tag, `-all`, indicates that mail from your domain should only come from servers identified in the SPF string. Anything coming from any other source is forging your domain. An alternative is `~all`, indicating the same thing but also indicating that mail servers should accept the message and flag it as forged instead of rejecting it outright. `-all` makes it harder for spammers to forge your domain successfully; it is the recommended setting. `~all` reduces the chances of email getting lost because an incorrect mail server was used to send mail. `~all` can be used if you don't want to take chances. + +The tags between identify eligible servers from which email to your domain can originate. + +- `mx` is a shorthand for all the hosts listed in MX records for your domain. If you've got a solitary mail server, `mx` is probably the best option. If you've got a backup mail server (a second MX record), using `mx` won't cause any problems. Your backup mail server will be identified as an authorized source for email although it will probably never send any. + +- The `a` tag lets you identify a specific host by name or IP address, letting you specify which hosts are authorized. You'd use `a` if you wanted to prevent the backup mail server from sending outgoing mail or if you wanted to identify hosts other than your own mail server that could send mail from your domain (e.g., putting your ISP's outgoing mail servers in the list so they'd be recognized when you had to send mail through them). + +For now, we're going to stick with the `mx` version. It's simpler and correct for most basic configurations, including those that handle multiple domains. To add the record, go to your DNS management interface and add a record of type TXT for your domain itself (i.e., a blank hostname) containing this string: + + v=spf1 mx -all + +If you're using Linode's DNS Manager, go to the domain zone page for the selected domain and add a new TXT record. The screen will look something like this once you've got it filled out: + +![Linode DNS manager add SPF TXT record](spf-record.png) + +If your DNS provider allows it (DNS Manager doesn't), you should also add a record of type SPF, filling it in the same way as you did the TXT record. + +{{< note >}} +The values for the DNS records above - and for the rest of this guide - are done in the style that Linode's DNS Manager needs them to be in. If you're using another provider, that respective system may require the values in a different style. For example freedns.afraid.org requires the values to be written in the style found in BIND zonefiles. Thus, the above SPF record's value would need to be wrapped in double-quotes like this: `"v=spf1 mx -all"`. You'll need to consult your DNS provider's documentation for the exact style required. +{{< /note >}} + +### Add the SPF policy agent to Postfix + +The Python SPF policy agent adds SPF policy-checking to Postfix. The SPF record for the sender's domain for incoming mail will be checked and, if it exists, mail will be handled accordingly. Perl has its own version, but it lacks the full capabilities of Python policy agent. + +1. If you are using SpamAssassin to filter spam, you may want to edit `/etc/postfix-policyd-spf-python/policyd-spf.conf` to change the `HELO_reject` and `Mail_From_reject` settings to `False`. This edit will cause the SPF policy agent to run its tests and add a message header with the results in it while _not_ rejecting any messages. You may also want to make this change if you want to see the results of the checks but not actually apply them to mail processing. Otherwise, just go with the standard settings. + +2. Edit `/etc/postfix/master.cf` and add the following entry at the end: + + {{< file "/etc/postfix/master.cf" resource >}} +policyd-spf unix - n n - 0 spawn + user=policyd-spf argv=/usr/bin/policyd-spf + +{{< /file >}} + + +3. Open `/etc/postfix/main.cf` and add this entry to increase the Postfix policy agent timeout, which will prevent Postfix from aborting the agent if transactions run a bit slowly: + + {{< file "/etc/postfix/main.cf" aconf >}} +policyd-spf_time_limit = 3600 + +{{< /file >}} + + +4. Edit the `smtpd_recipient_restrictions` entry to add a `check_policy_service` entry: + + {{< file "/etc/postfix/main.cf" aconf >}} +smtpd_recipient_restrictions = + ... + reject_unauth_destination, + check_policy_service unix:private/policyd-spf, + ... + +{{< /file >}} + + + Make sure to add the `check_policy_service` entry **after** the `reject_unauth_destination` entry to avoid having your system become an open relay. If `reject_unauth_destination` is the last item in your restrictions list, add the comma after it and omit the comma at the end of the `check_policy_service` item above. + +5. Restart Postfix: + + systemctl restart postfix + +You can check the operation of the policy agent by looking at raw headers on incoming email messages for the SPF results header. The header the policy agent adds to messages should look something like this: + + Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=127.0.0.1; helo=mail.example.com; envelope-from=text@example.com; receiver=tknarr@silverglass.org + +This header indicates a successful check against the SPF policy of the sending domain. If you changed the policy agent settings in Step 1 to not reject mail that fails the SPF check, you may see Fail results in this header. You won't see this header on outgoing or local mail. + +The SPF policy agent also logs to `/var/log/mail.log`. In the `mail.log` file you'll see messages like this from the policy agent: + + Jan 7 06:24:44 arachnae policyd-spf[21065]: None; identity=helo; client-ip=127.0.0.1; helo=mail.example.com; envelope-from=test@example.com; receiver=tknarr@silverglass.org + Jan 7 06:24:44 arachnae policyd-spf[21065]: Pass; identity=mailfrom; client-ip=127.0.0.1; helo=mail.example.com; envelope-from=test@example.com; receiver=tknarr@silverglass.org + +The first message is a check of the HELO command, in this case indicating that there wasn't any SPF information matching the HELO (which is perfectly OK). The second message is the check against the envelope From address, and indicates the address passed the check and is coming from one of the outgoing mail servers the sender's domain has said should be sending mail for that domain. There may be other statuses in the first field after the colon indicating failure, temporary or permanent errors and so on. + +## Set up DKIM + +DKIM involves setting up the OpenDKIM package, hooking it into Postfix, and adding DNS records. + +### Configure OpenDKIM + +1. The main OpenDKIM configuration file `/etc/opendkim.conf` needs to look like this: + + {{< file "/etc/opendkim.conf" aconf >}} +# This is a basic configuration that can easily be adapted to suit a standard +# installation. For more advanced options, see opendkim.conf(5) and/or +# /usr/share/doc/opendkim/examples/opendkim.conf.sample. + +# Log to syslog +Syslog yes +# Required to use local socket with MTAs that access the socket as a non- +# privileged user (e.g. Postfix) +UMask 002 +# OpenDKIM user +# Remember to add user postfix to group opendkim +UserID opendkim + +# Map domains in From addresses to keys used to sign messages +KeyTable /etc/opendkim/key.table +SigningTable refile:/etc/opendkim/signing.table + +# Hosts to ignore when verifying signatures +ExternalIgnoreList /etc/opendkim/trusted.hosts +InternalHosts /etc/opendkim/trusted.hosts + +# Commonly-used options; the commented-out versions show the defaults. +Canonicalization relaxed/simple +Mode sv +SubDomains no +#ADSPAction continue +AutoRestart yes +AutoRestartRate 10/1M +Background yes +DNSTimeout 5 +SignatureAlgorithm rsa-sha256 + +# Always oversign From (sign using actual From and a null From to prevent +# malicious signatures header fields (From and/or others) between the signer +# and the verifier. From is oversigned by default in the Debian package +# because it is often the identity key used by reputation systems and thus +# somewhat security sensitive. +OversignHeaders From + +# Define the location of the Socket and PID files +Socket local:/var/spool/postfix/opendkim/opendkim.sock +PidFile /var/run/opendkim/opendkim.pid + +{{< /file >}} + + + Edit `/etc/opendkim.conf` and replace it's contents with the above. + +2. Ensure that file permissions are set correctly: + + chmod u=rw,go=r /etc/opendkim.conf + +3. Create the directories to hold OpenDKIM's data files, assign ownership to the `opendkim` user, and restrict the file permissions: + + mkdir /etc/opendkim + mkdir /etc/opendkim/keys + chown -R opendkim:opendkim /etc/opendkim + chmod go-rw /etc/opendkim/keys + +4. Create the signing table `/etc/opendkim/signing.table`. It needs to have one line per domain that you handle email for. Each line should look like this: + + {{< file "/etc/opendkim/signing.table" >}} +*@example.com example + +{{< /file >}} + + + Replace `example.com` with your domain and `example` with a short name for the domain. The first field is a pattern that matches e-mail addresses. The second field is a name for the key table entry that should be used to sign mail from that address. For simplicity's sake, we're going to set up one key for all addresses in a domain. + +5. Create the key table `/etc/opendkim/key.table`. It needs to have one line per short domain name in the signing table. Each line should look like this: + + {{< file "/etc/opendkim/key.table" resource >}} +example example.com:YYYYMM:/etc/opendkim/keys/example.private + +{{< /file >}} + + + Replace `example` with the `example` value you used for the domain in the signing table (make sure to catch the second occurrence at the end, where it's followed by `.private`). Replace `example.com` with your domain name and replace the `YYYYMM` with the current 4-digit year and 2-digit month (this is referred to as the selector). The first field connects the signing and key tables. + + The second field is broken down into 3 sections separated by colons. + + - The first section is the domain name for which the key is used. + - The second section is a selector used when looking up key records in DNS. + - The third section names the file containing the signing key for the domain. + + {{< note >}} +The flow for DKIM lookup starts with the sender's address. The signing table is scanned until an entry whose pattern (first item) matches the address is found. Then, the second item's value is used to locate the entry in the key table whose key information will be used. For incoming mail the domain and selector are then used to find the public key TXT record in DNS and that public key is used to validate the signature. For outgoing mail the private key is read from the named file and used to generate the signature on the message. +{{< /note >}} + +6. Create the trusted hosts file `/etc/opendkim/trusted.hosts`. Its contents need to be: + + {{< file "/etc/opendkim/trusted.hosts" resource >}} +127.0.0.1 +::1 +localhost +myhostname +myhostname.example.com +example.com + +{{< /file >}} + + + When creating the file, change `myhostname` to the name of your server and replace `example.com` with your own domain name. We're identifying the hosts that users will be submitting mail through and should have outgoing mail signed, which for basic configurations will be your own mail server. + +7. Make sure the ownership and permissions on `/etc/opendkim` and it's contents are correct (`opendkim` should own everything, the `keys` directory should only be accessible by the owner) by running the following commands: + + chown -R opendkim:opendkim /etc/opendkim + chmod -R go-rwx /etc/opendkim/keys + +8. Generate keys for each domain: + + opendkim-genkey -b 2048 -h rsa-sha256 -r -s YYYYMM -d example.com -v + + Replace `YYYYMM` with the current year and month as in the key table. This will give you two files, `YYYYMM.private` containing the key and `YYYYMM.txt` containing the TXT record you'll need to set up DNS. Rename the files so they have names matching the third section of the second field of the key table for the domain: + + mv YYYYMM.private example.private + mv YYYYMM.txt example.txt + + Repeat the commands in this step for every entry in the key table. The `-b 2048` indicates the number of bits in the RSA key pair used for signing and verification. 1024 bits is the minimum, but with modern hardware 2048 bits is safer. (It's possible 4096 bits will be required at some point.) + +9. Make sure the ownership, permissions and contents on `/etc/opendkim` are correct by running the following commands: + + cd /etc + chown -R opendkim:opendkim /etc/opendkim + chmod -R go-rw /etc/opendkim/keys + +10. Check that OpenDKIM starts correctly: + + systemctl restart opendkim + + You should not get error messages, but if you do, use: + + systemctl status -l opendkim + + to get the status and untruncated error messages. + +### Set up DNS + +As with SPF, DKIM uses TXT records to hold information about the signing key for each domain. Using YYYYMM as above, you need to make a TXT record for the host `YYYYMM._domainkey` for each domain you handle mail for. Its value can be found in the `example.txt` file for the domain. Those files look like this: + +{{< file "example.txt" resource >}} +201510._domainkey IN TXT ( "**v=DKIM1; h=rsa-sha256; k=rsa; s=email; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5oIUrFDWZK7F4thFxpZa2or6jBEX3cSL6b2TJdPkO5iNn9vHNXhNX31nOefN8FksX94YbLJ8NHcFPbaZTW8R2HthYxRaCyqodxlLHibg8aHdfa+bxKeiI/xABRuAM0WG0JEDSyakMFqIO40ghj/h7DUc/4OXNdeQhrKDTlgf2bd+FjpJ3bNAFcMYa3Oeju33b2Tp+PdtqIwXR" + "ZksfuXh7m30kuyavp3Uaso145DRBaJZA55lNxmHWMgMjO+YjNeuR6j4oQqyGwzPaVcSdOG8Js2mXt+J3Hr+nNmJGxZUUW4Uw5ws08wT9opRgSpn+ThX2d1AgQePpGrWOamC3PdcwIDAQAB**" ) ; ----- DKIM key 201510 for example.com + +{{< /file >}} + + +The value inside the parentheses is what you want. Select and copy the entire region from (but not including) the double-quote before `v=DKIM1` on up to (but not including) the final double-quote before the closing parentheses. Then edit out the double-quotes within the copied text and the whitespace between them. Also change `h=rsa-sha256` to `h=sha256`. From the above file the result would be: + +{{< file "example-copied.txt" resource >}} +v=DKIM1; h=sha256; k=rsa; s=email; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5oIUrFDWZK7F4thFxpZa2or6jBEX3cSL6b2TJdPkO5iNn9vHNXhNX31nOefN8FksX94YbLJ8NHcFPbaZTW8R2HthYxRaCyqodxlLHibg8aHdfa+bxKeiI/xABRuAM0WG0JEDSyakMFqIO40ghj/h7DUc/4OXNdeQhrKDTlgf2bd+FjpJ3bNAFcMYa3Oeju33b2Tp+PdtqIwXRZksfuXh7m30kuyavp3Uaso145DRBaJZA55lNxmHWMgMjO+YjNeuR6j4oQqyGwzPaVcSdOG8Js2mXt+J3Hr+nNmJGxZUUW4Uw5ws08wT9opRgSpn+ThX2d1AgQePpGrWOamC3PdcwIDAQAB + +{{< /file >}} + + +Paste that into the value for the TXT record. + +If you're using Linode's DNS manager, this is what the add TXT record screen will look like when you have it filled out: + +![Linode DNS manager add SPF TXT record](dkim-record.png) + +Repeat this for every domain you handle mail for, using the `.txt` file for that domain. + +### Test your configuration + +Test the keys for correct signing and verification using the `opendkim-testkey` command: + + opendkim-testkey -d example.com -s YYYYMM + +If everything is OK you shouldn't get any output. If you want to see more information, add `-vvv` to the end of the command. That produces verbose debugging output. The last message should be "key OK". Just before that you may see a "key not secure" message. That's normal and doesn't signal an error, it just means your domain isn't set up for DNSSEC yet. + +### Hook OpenDKIM into Postfix + +1. Create the OpenDKIM socket directory in Postfix's work area and make sure it has the correct ownership: + + mkdir /var/spool/postfix/opendkim + chown opendkim:postfix /var/spool/postfix/opendkim + +2. Set the correct socket for Postfix in the OpenDKIM defaults file `/etc/default/opendkim`: + + {{< file "/etc/default/opendkim" >}} +# Command-line options specified here will override the contents of +# /etc/opendkim.conf. See opendkim(8) for a complete list of options. +#DAEMON_OPTS="" +# +# Uncomment to specify an alternate socket +# Note that setting this will override any Socket value in opendkim.conf +SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock" +#SOCKET="inet:54321" # listen on all interfaces on port 54321 +#SOCKET="inet:12345@localhost" # listen on loopback on port 12345 +#SOCKET="inet:12345@192.0.2.1" # listen on 192.0.2.1 on port 12345 + +{{< /file >}} + + + + Uncomment the first SOCKET line and edit it so it matches the uncommented line in the above file. The path to the socket is different from the default because on Debian 9 the Postfix process that handles mail runs in a chroot jail and can't access the normal location. + +3. Edit `/etc/postfix/main.cf` and add a section to activate processing of e-mail through the OpenDKIM daemon: + + {{< file "/etc/postfix/main.cf" aconf >}} +# Milter configuration +# OpenDKIM +milter_default_action = accept +# Postfix ≥ 2.6 milter_protocol = 6, Postfix ≤ 2.5 milter_protocol = 2 +milter_protocol = 6 +smtpd_milters = local:opendkim/opendkim.sock +non_smtpd_milters = local:opendkim/opendkim.sock + +{{< /file >}} + + + You can put this anywhere in the file. The usual practice is to put it after the `smtpd_recipient_restrictions` entry. You'll notice the path to the socket isn't the same here as it was in the `/etc/defaults/opendkim` file. That's because of Postfix's chroot jail, the path here is the path within that restricted view of the filesystem instead of within the actual filesystem. + +4. Restart the OpenDKIM daemon so it sets up the correct socket for Postfix: + + systemctl restart opendkim + +5. Restart Postfix so it starts using OpenDKIM when processing mail: + + systemctl restart postfix + +### Verify that everything's fully operational + +The easiest way to verify that everything's working is to send a test e-mail to `check-auth@verifier.port25.com` using an email client configured to submit mail to the submission port on your mail server. It will analyze your message and mail you a report indicating whether your email was signed correctly or not. It also reports on a number of other things such as SPF configuration and SpamAssassin flagging of your domain. If there's a problem, it'll report what the problem was. + +## Optional: Set up Author Domain Signing Practices (ADSP) + +As a final item, you can add an ADSP policy to your domain saying that all emails from your domain should be DKIM-signed. As usual, it's done with a TXT record for host `_adsp._domainkey` in your domain with a value of `dkim=all`. If you're using Linode's DNS Manager, the screen for the new text record will look like this: + +![Linode DNS Manager add ADSP TXT record](adsp-record.png) + +You don't need to set this up, but doing so makes it harder for anyone to forge email from your domains because recipient mail servers will see the lack of a DKIM signature and reject the message. + +## Optional: Set up Domain Message Authentication, Reporting & Conformance (DMARC) + +The DMARC DNS record can be added to advise mail servers what you think they should do with emails claiming to be from your domain that fail validation with SPF and/or DKIM. DMARC also allows you to request reports about mail that fails to pass one or more validation check. DMARC should only be set up if you have SPF and DKIM set up and operating successfully. If you add the DMARC DNS record without having both SPF and DKIM in place, messages from your domain will fail validation which may cause them to be discarded or relegated to a spam folder. + +The DMARC record is a TXT record for host `_dmarc` in your domain containing the following recommended values: + + v=DMARC1;p=quarantine;sp=quarantine;adkim=r;aspf=r + +This requests mail servers to quarantine (do not discard, but separate from regular messages) any email that fails either SPF or DKIM checks. No reporting is requested. Very few mail servers implement the software to generate reports on failed messages, so it is often unnecessary to request them. If you do wish to request reports, the value would be similar to this example, added as a single string: + + v=DMARC1;p=quarantine;sp=quarantine;adkim=r;aspf=r;fo=1;rf=afrf;rua=mailto:user@example.com + +Replace `user@example.com` in the `mailto:` URL with your own email or an email address you own dedicated to receiving reports (an address such as `dmarc@example.com`). This requests aggregated reports in XML showing how many messages fell into each combination of pass and fail results and the mail server addresses sending them. If you're using Linode's DNS Manager, the screen for the new text record will look like this: + +![Linode DNS Manager add DMARC TXT record](dmarc-record.png) + +DMARC records have a number of available tags and options. These tags are used to control your authentication settings: + +* `v` specifies the protocol version, in this case `DMARC1`. +* `p` determines the policy for the root domain, such as "example.com." The available options: + * `quarantine` instructs that if an email fails validation, the recipient should set it aside for processing. + * `reject` requests that the receiving mail server reject the emails that fail validation. + * `none` requests that the receiver take no action if an email does not pass validation. +* `sp` determines the policy for subdomains, such as "subdomain.example.com." It takes the same arguments as the `p` tag. +* `adkim` specifies the alignment mode for DKIM, which determines how strictly DKIM records are validated. The available options are: + * `r` relaxed alignment mode, DKIM authentication is less strictly enforced. + * `s` strict alignment mode. Only an exact match with the DKIM entry for the root domain will be seen as validated. +* `aspf` determines the alignment mode for SPF verification. It takes the same arguments as `adkim`. + +If you wish to receive authentication failure reports, DMARC provides a number of configuration options. You can use the following tags to customize the formatting of your reports, as well as the criteria for report creation. + +* `rua` specifies the email address that will receive aggregate reports. This uses the `mailto:user@example.com` syntax, and accepts multiple addresses separated by commas. Aggregate reports are usually generated once per day. +* `ruf` specifies the email address that will receive detailed authentication failure reports. This takes the same arguments as `rua`. With this option, each authentication failure would result in a separate report. +* `fo` allows you to specify which failed authentication methods will be reported. One or more of the following options can be used: + * `0` will request a report if *all* authentication methods fail. For example, if an SPF check were to fail but DKIM authentication was successful, a report would not be sent. + * `1` requests a report if *any* authentication check fails. + * `d` requests a report if a DKIM check fails. + * `s` requests a report if an SPF check fails. +* `rf` determines the format used for authentication failure reports. Available options: + * `afrf` uses the Abuse Report format as defined by [RFC 5965](https://www.ietf.org/rfc/rfc5965.txt). + * `iodef` uses the Incident Object Description Exchange format as defined by [RFC 5070](https://www.ietf.org/rfc/rfc5070.txt). + +## Key rotation + +The reason the YYYYMM format is used for the selector is that best practice calls for changing the DKIM signing keys every so often (monthly is recommended, and no longer than every 6 months). To do that without disrupting messages in transit, you generate the new keys using a new selector. The process is: + +1. Generate new keys as in step 8 of [Configure OpenDKIM](#configure-opendkim). Do this in a scratch directory, not directly in `/etc/opendkim/keys`. Use the current year and month for the YYYYMM selector value, so it's different from the selector currently in use. + +2. Use the newly-generated `.txt` files to add the new keys to DNS as in the DKIM [Set Up DNS](#set-up-dns) section, using the new YYYYMM selector in the host names. Don't remove or alter the existing DKIM TXT records. Once this is done, verify the new key data using the following command (replacing example.com, example and YYYYMM with the appropriate values): + + opendkim-testkey -d example.com -s YYYYMM -k example.private + + Add the `-vvv` switch to get debugging output if you need it to diagnose any problems. Correct any problems before proceeding, beginning to use the new private key file and selector when `opendkim-testkey` doesn't indicate a successful verification will cause problems with your email including non-receipt of messages. + +3. Stop Postfix and OpenDKIM with `systemctl stop postfix opendkim` so that they won't be processing mail while you're changing out keys. + +4. Copy the newly-generated `.private` files into place and make sure their ownership and permissions are correct by running these commands from the directory in which you generated the key files: + + cp *.private /etc/opendkim/keys/ + chown opendkim:opendkim /etc/opendkim/keys/* + chmod go-rw /etc/opendkim/keys/* + + Use the `opendkim-testkey` command as described above to ensure that your new record is propagated before you continue. + +5. Edit `/etc/opendkim/key.table` and change the old YYYYMM values to the new selector, reflecting the current year and month. Save the file. + +6. Restart OpenDKIM and Postfix by: + + systemctl start opendkim + systemctl start postfix + + Make sure they both start without any errors. + +7. After a couple of weeks, all email in transit should either have been delivered or bounced and the old DKIM key information in DNS won't be needed anymore. Delete the old `YYYYMM._domainkey` TXT records in each of your domains, leaving just the newest ones (most recent year and month). Don't worry if you forget and leave the old keys around longer than planned. There's no security issue. Removing the obsolete records is more a matter of keeping things neat and tidy than anything else. diff --git a/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/spf-record.png b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/spf-record.png new file mode 100644 index 00000000000..639276e5604 Binary files /dev/null and b/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-9/spf-record.png differ diff --git a/docs/game-servers/minecraft-with-mcmyadmin-on-debian/Installing_McMyAdmin_for_Minecraft_on_Debian_smg.png b/docs/game-servers/minecraft-with-mcmyadmin-on-debian/Installing_McMyAdmin_for_Minecraft_on_Debian_smg.png new file mode 100644 index 00000000000..1ddd831ad7a Binary files /dev/null and b/docs/game-servers/minecraft-with-mcmyadmin-on-debian/Installing_McMyAdmin_for_Minecraft_on_Debian_smg.png differ diff --git a/docs/game-servers/minecraft-with-mcmyadmin-on-debian/index.md b/docs/game-servers/minecraft-with-mcmyadmin-on-debian/index.md index 2eeb1876abe..b1799e3c386 100644 --- a/docs/game-servers/minecraft-with-mcmyadmin-on-debian/index.md +++ b/docs/game-servers/minecraft-with-mcmyadmin-on-debian/index.md @@ -5,7 +5,7 @@ author: description: 'McMyAdmin is one of the most popular Minecraft server control panels available. It boasts compatibility with third party mods, heavy focus on security and a sleek web interface for managing your server. This guide covers the installation and configuration of a new McMyAdmin server on a Linode running Debian 7 or 8.' keywords: ["minecraft", "mcmyadmin", "debian", "debian jessie", "debian wheezy", "jessie", "wheezy", "debian 7", "debian 8"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2016-02-03 +modified: 2018-12-18 modified_by: name: Linode published: 2015-02-05 @@ -16,6 +16,8 @@ external_resources: aliases: ['applications/game-servers/minecraft-with-mcmyadmin-on-debian/'] --- +![Installing McMyAdmin for Minecraft on Debian](Installing_McMyAdmin_for_Minecraft_on_Debian_smg.png "Installing McMyAdmin for Minecraft on Debian") + [McMyAdmin](https://mcmyadmin.com/) is one of the most popular Minecraft server control panels available. It boasts compatibility with third party mods, heavy focus on security and a sleek web interface for managing your server. This guide covers the installation and configuration of a new McMyAdmin server on a Linode running Debian 7 or 8. Be aware that to actually play on a Minecraft server you must also have the game client from [minecraft.net](https://minecraft.net/). ## Before You Begin diff --git a/docs/languages/_index.md b/docs/languages/_index.md new file mode 100644 index 00000000000..d561addd164 --- /dev/null +++ b/docs/languages/_index.md @@ -0,0 +1,4 @@ +--- +title: Languages +description: "Select a programming language to view all related guides." +--- \ No newline at end of file diff --git a/docs/languages/go/_index.md b/docs/languages/go/_index.md new file mode 100644 index 00000000000..cb5f44aec42 --- /dev/null +++ b/docs/languages/go/_index.md @@ -0,0 +1,3 @@ +--- +title: Go +--- \ No newline at end of file diff --git a/docs/languages/java/_index.md b/docs/languages/java/_index.md new file mode 100644 index 00000000000..55632d7a3f7 --- /dev/null +++ b/docs/languages/java/_index.md @@ -0,0 +1,3 @@ +--- +title: Java +--- \ No newline at end of file diff --git a/docs/languages/javascript/_index.md b/docs/languages/javascript/_index.md new file mode 100644 index 00000000000..b5ff678c4b6 --- /dev/null +++ b/docs/languages/javascript/_index.md @@ -0,0 +1,3 @@ +--- +title: JavaScript +--- \ No newline at end of file diff --git a/docs/languages/julia/_index.md b/docs/languages/julia/_index.md new file mode 100644 index 00000000000..2ea9bdcbe49 --- /dev/null +++ b/docs/languages/julia/_index.md @@ -0,0 +1,3 @@ +--- +title: Julia +--- \ No newline at end of file diff --git a/docs/languages/perl/_index.md b/docs/languages/perl/_index.md new file mode 100644 index 00000000000..31032eb1441 --- /dev/null +++ b/docs/languages/perl/_index.md @@ -0,0 +1,3 @@ +--- +title: Perl +--- \ No newline at end of file diff --git a/docs/languages/python/_index.md b/docs/languages/python/_index.md new file mode 100644 index 00000000000..9bc4094feb6 --- /dev/null +++ b/docs/languages/python/_index.md @@ -0,0 +1,3 @@ +--- +title: Python +--- \ No newline at end of file diff --git a/docs/languages/r/_index.md b/docs/languages/r/_index.md new file mode 100644 index 00000000000..2cda49f745a --- /dev/null +++ b/docs/languages/r/_index.md @@ -0,0 +1,3 @@ +--- +title: R +--- \ No newline at end of file diff --git a/docs/languages/ruby/_index.md b/docs/languages/ruby/_index.md new file mode 100644 index 00000000000..9629be33d05 --- /dev/null +++ b/docs/languages/ruby/_index.md @@ -0,0 +1,3 @@ +--- +title: Ruby +--- \ No newline at end of file diff --git a/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/Set_Up_an_IPv6_Tunnel_on_Your_Linode_smg.jpg b/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/Set_Up_an_IPv6_Tunnel_on_Your_Linode_smg.jpg new file mode 100644 index 00000000000..e52dc445b44 Binary files /dev/null and b/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/Set_Up_an_IPv6_Tunnel_on_Your_Linode_smg.jpg differ diff --git a/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/index.md b/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/index.md index 63d5f67f8bb..91f1c14d234 100644 --- a/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/index.md +++ b/docs/networking/set-up-an-ipv6-tunnel-on-your-linode/index.md @@ -6,13 +6,15 @@ description: 'How to set up an IPv6 tunnel on your Linode.' keywords: ["ipv6", "tunnel", "broker", "networking"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' aliases: ['networking/ipv6-tunnels/'] -modified: 2018-05-15 +modified: 2018-12-11 modified_by: name: Linode published: 2011-04-29 title: Set Up an IPv6 Tunnel on Your Linode --- +![Set up an IPv6 Tunnel on Your Linode](Set_Up_an_IPv6_Tunnel_on_Your_Linode_smg.jpg) + As IPv4 address exhaustion nears, many people are making the switch to IPv6. Linode offers [native IPv6](/docs/networking/native-ipv6-networking/) addresses in all locations. An IPv6 tunnel lets a system reach an IPv6 network using existing IPv4 connectivity. Follow this guide if you: diff --git a/docs/platform/disk-images/linode-backup-service/The_Linode_Backup_Service_smg.jpg b/docs/platform/disk-images/linode-backup-service/The_Linode_Backup_Service_smg.jpg new file mode 100644 index 00000000000..b257859cbc7 Binary files /dev/null and b/docs/platform/disk-images/linode-backup-service/The_Linode_Backup_Service_smg.jpg differ diff --git a/docs/platform/disk-images/linode-backup-service/index.md b/docs/platform/disk-images/linode-backup-service/index.md index 040de5d941a..629ddb288a1 100644 --- a/docs/platform/disk-images/linode-backup-service/index.md +++ b/docs/platform/disk-images/linode-backup-service/index.md @@ -5,13 +5,15 @@ description: 'Use the Linode Backup Service to protect and secure your data.' keywords: ["backup service", "linode platform", "linode backup service", "enable a backup", "manage a backup", "schedule a backup", "disable a backup", "restore from a backup", "boot from a backup"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' aliases: ['backup-service/','platform/backup-service/', 'security/backups/linode-backup-service/','platform/linode-backup-service/'] -modified: 2018-10-18 +modified: 2018-12-11 modified_by: name: Linode published: 2012-03-14 title: 'The Linode Backup Service' --- +![The Linode Backup Service](The_Linode_Backup_Service_smg.jpg) + The *Linode Backup Service* is a subscription service add-on that automatically performs daily, weekly, and biweekly backups of your Linode. It's affordable, easy to use, and provides peace of mind. This guide explains how to enable and schedule your backups, make a manual backup snapshot, restore from a backup, and disable the Backup Service. ## Pricing diff --git a/docs/security/encrypt-data-disk-with-dm-crypt/How_to_Encrypt_Your_Data_with_dm-crypt_smg.png b/docs/security/encrypt-data-disk-with-dm-crypt/How_to_Encrypt_Your_Data_with_dm-crypt_smg.png new file mode 100644 index 00000000000..d3910ff2ec3 Binary files /dev/null and b/docs/security/encrypt-data-disk-with-dm-crypt/How_to_Encrypt_Your_Data_with_dm-crypt_smg.png differ diff --git a/docs/security/encrypt-data-disk-with-dm-crypt/index.md b/docs/security/encrypt-data-disk-with-dm-crypt/index.md index c12f009b7f9..5c693027da3 100644 --- a/docs/security/encrypt-data-disk-with-dm-crypt/index.md +++ b/docs/security/encrypt-data-disk-with-dm-crypt/index.md @@ -7,7 +7,7 @@ og_description: 'dm-crypt is a transparent encryption subsystem. In this guide y keywords: ['dm-crypt', 'encryption', 'encrypt', 'luks'] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' published: 2017-12-18 -modified: 2017-12-18 +modified: 2018-12-18 modified_by: name: Linode title: 'How to Encrypt Your Data with dm-crypt' @@ -15,6 +15,8 @@ contributor: name: Alexandru Andrei --- +![How to Encrypt Your Data with dm-crypt](How_to_Encrypt_Your_Data_with_dm-crypt_smg.png "How to Encrypt Your Data with dm-crypt") + dm-crypt is a transparent disk encryption subsystem. In this guide you will learn how to encrypt disks, partition, swap and even use files as encrypted, and portable containers for your sensitive data. diff --git a/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/Patching_OpenSSL_for_the_Heartbleed_Vulnerability_smg.png b/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/Patching_OpenSSL_for_the_Heartbleed_Vulnerability_smg.png new file mode 100644 index 00000000000..c549745cbbc Binary files /dev/null and b/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/Patching_OpenSSL_for_the_Heartbleed_Vulnerability_smg.png differ diff --git a/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/index.md b/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/index.md index cdbf459ffa3..8ca5e85f8e8 100644 --- a/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/index.md +++ b/docs/security/security-patches/patching-openssl-for-the-heartbleed-vulnerability/index.md @@ -6,7 +6,7 @@ description: 'Instructions on patching your Linode against the Heartbleed bug.' keywords: ["openssl", "heartbleed", "security", "patch", "ubuntu", "debian", "centos", "fedora"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' aliases: ['security/openssl-heartbleed/','security/patching-openssl-for-the-heartbleed-vulnerability/'] -modified: 2014-06-17 +modified: 2018-12-18 modified_by: name: Alex Fornuto published: 2014-04-08 @@ -15,6 +15,8 @@ external_resources: - '[Heartbleed.com](http://heartbleed.com/)' --- +![Patching OpenSSL for the Heartbleed Vulnerability](Patching_OpenSSL_for_the_Heartbleed_Vulnerability_smg.png "Patching OpenSSL for the Heartbleed Vulnerability") + A security vulnerability in OpenSSL dubbed **Heartbleed** has been found. This vulnerability was only recently discovered openly, but has been "in the wild" for over a year. It's important to update your local version of OpenSSL to correct this issue. This brief guide will walk you through ensuring that the patch is installed on your Linode, and suggest additional steps you can take to ensure your server's security. As always, we suggest having backups of your system prior to making any changes. This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you're not familiar with the `sudo` command, you can check our [Users and Groups](/docs/tools-reference/linux-users-and-groups) guide. diff --git a/docs/security/upgrading/upgrade-debian-to-the-newest-release/index.md b/docs/security/upgrading/upgrade-debian-to-the-newest-release/index.md new file mode 100644 index 00000000000..c54cf45d714 --- /dev/null +++ b/docs/security/upgrading/upgrade-debian-to-the-newest-release/index.md @@ -0,0 +1,160 @@ +--- +author: + name: Linode + email: docs@linode.com +description: 'How to upgrade your Debian system.' +keywords: ['debian','upgrade','update'] +aliases: ['security/upgrading/upgrade-to-debian-8-jessie/'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-11 +modified: 2018-12-14 +modified_by: + name: Linode +title: "Upgrade Debian to the Newest Release" +--- + +Debian repositories can be tracked either by codename (Wheezy, Jessie, etc.), or by status name (stable, testing, etc.). For example, Debian 9 Stretch is the *stable* release at the time of this writing; the status of Debian 8 (Jessie) is *oldstable*. Debian stable releases are eventually managed by the [Debian Long Term Support](https://wiki.debian.org/LTS/) (LTS) team for a total lifespan of about 5 years. + +Linode offers Debian's [stable](https://wiki.debian.org/DebianStable) and [oldstable](https://wiki.debian.org/DebianOldStable) releases. When exclusively tracking the stable releases with APT, your system will upgrade whenever the stable release reaches its end of life. For example, if you're tracking the stable release of Debian 8 and it reaches its end of life, your system will make available a number of new packages which will upgrade you to Debian 9. + +On the other hand, if you're currently tracking repositories by codename, as Debian does by default, you will never upgrade beyond that codename release. This is the safest option and you can still manually upgrade to a newer Debian codename or release status name at any time. + +{{< caution >}} +While upstream maintainers try to ensure cross-compatibility and problem-free upgrades, there is risk involved in upgrading operating system versions. +{{< /caution >}} + +## Before You Begin + +- You will need root access to your Linode, or a user account with `sudo` privileges. + +- **Back up any important data stored on your Linode!** If you subscribe to the Linode Backups service, we recommend taking a [manual snapshot](/docs/platform/disk-images/linode-backup-service/#take-a-manual-snapshot) before upgrading your system. If you use a different backup service or application, you should do a manual backup now. + + {{< note >}} +You may also want to back up your configuration files (usually located in `/etc/`) in case they have changed in later versions of the software you are using. See our [backup guides](/docs/security/backups/) for more information. +{{< /note >}} + + +## Prepare to Upgrade + +1. Verify that you are booting with Debian's kernel using the *GRUB 2* [boot setting](/docs/platform/how-to-change-your-linodes-kernel/) in the Linode Cloud Manager. We recommend you use the distribution-supplied kernel unless you have a specific reason not to. + +2. Exit the SSH session if you're currently logged in to one and instead open a Lish session to your Linode. Lish will give you continuous access to your Linode whereas SSH could disconnect during the upgrade. Read more about Lish [here](/docs/platform/manager/using-the-linode-shell-lish/). + +3. Install all available updates for your current Debian system: + + sudo apt update && sudo apt upgrade + +4. If you've set APT to pin any packages to a specific Debian version other than stable, You'll need to disable APT pinning for those packages if you want them upgraded to those offered in the newest release. + + +5. You may want to stop services which are non-essential to the system but important to your setup, such as a database service. This would be to ensure a graceful shutdown of the service to prevent data loss or system locks from causing problems. To stop a service, enter the following command, replacing `mariadb` with the name of the service you want to stop: + + sudo systemctl stop mariadb + + You can view all enabled services with: + + sudo systemctl list-unit-files --state=enabled + + View all currently running services: + + sudo systemctl list-units --state=running + + +## Upgrade Debian + +1. Edit your `sources.list` file to change all instances of the current codename to the new release codename. The example of upgrading from Debian 8 (Jessie) to Debian 9 (Stretch) is used below, so `jessie` is changed to `stretch` (or, alternatively from `jessie` to `stable`). + + {{< file "/etc/apt/sources.list" >}} +deb http://mirrors.linode.com/debian stretch main +deb-src http://mirrors.linode.com/debian stretch main + +deb http://mirrors.linode.com/debian-security/ stretch/updates main +deb-src http://mirrors.linode.com/debian-security/ stretch/updates main + +# stretch-updates, previously known as 'volatile' +deb http://mirrors.linode.com/debian stretch-updates main +deb-src http://mirrors.linode.com/debian stretch-updates main +{{< /file >}} + + {{< note >}} +Ensure any third party repositories are also tracking `stretch`. You will need to check with the maintainers of each package to ensure that their own repositories have been updated. +{{< /note >}} + +1. Update your package lists and remove any old packages which were previously downloaded for installation: + + sudo apt update + sudo apt-get clean + +1. The Debian 8 release notes recommend a [two-part](https://www.debian.org/releases/stable/amd64/release-notes/ch-upgrading.en.html#minimal-upgrade) upgrade path to avoid removing packages you may want to keep. Perform the minimal upgrade. + + sudo apt upgrade + + - During the upgrade process, you will prompted whether you want to replace or keep the current GRUB 2 file. This is because Linode must edit `/etc/default/grub` from upstream to work properly with our infrastructure. + + ![Keep current Grub 2 configuration](keep-current-grub2-configuration.png) + + Choose `Keep the local version currently installed`. Further prompts about installing GRUB should be answered with installing to `/dev/sda`, then `Continue without installing GRUB`. GRUB is not needed in your disk MBR because your Linode boots from a GRUB installation provided by Linode's host servers. + + - During the upgrade process, you'll be prompted to review configuration files which you've modified to decide whether to keep or replace them with the upstream default file. An example: + + {{< output >}} +Configuration file '/etc/mysql/my.cnf' +==> Modified (by you or by a script) since installation. +==> Package distributor has shipped an updated version. +What would you like to do about it ? Your options are: +Y or I : install the package maintainer's version +N or O : keep your currently-installed version +D : show the differences between the versions +{{< /output >}} + + - If your system is running Fail2ban, the upgrade will end with the error shown below. This is a [known issue](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=860397). See the [troubleshooting](/docs/security/upgrading/upgrade-debian-to-the-newest-release/#fail2ban) section of this page to fix before proceeding further. + + {{< output >}} +Errors were encountered while processing: + fail2ban +E: Sub-process /usr/bin/dpkg returned an error code (1) +{{< /output >}} + +1. Once the minimal upgrade above is completed, start the main upgrade: + + sudo apt dist-upgrade + +1. Reboot your system when the upgrade completes. You should still be in Lish. Monitor the Linode's console output for errors as the system shuts down and reboots. Your Linode is now running the newest version of Debian Stable. + +1. Remove old and unused packages: + + sudo apt-get autoremove + + +## Troubleshooting + +Below are some known issues you may encounter when upgrading Debian. These are mainly just issues reported by our customers so you'll want to monitor the *[debian-announce](https://lists.debian.org/debian-announce/)* mailing list for more comprehensive information, and the lists of any third party packages you will install. + +### Fail2ban + +When upgrading from Debian 8 to 9, you may experience problems because of a duplicate configuration option in `/etc/fail2ban/jail.local` if you copied it directly from `/etc/fail2ban/jail.conf`. This is currently a [known issue](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=860397). To fix this: + +1. Comment out `port = anyport` in `/etc/fail2ban/jail.local` (around line 155). The block should look similar to below: + + {{< file "/etc/fail2ban/jail.local" >}} +[pam-generic] + +enabled = false +# pam-generic filter can be customized to monitor specific subset of 'tty's +filter = pam-generic +# port actually must be irrelevant but lets leave it all for some possible uses +port = all +banaction = iptables-allports +#port = anyport +logpath = /var/log/auth.log +maxretry = 6 +{{< /file >}} + +1. Tell `dpkg` to reconfigure anything necessary: + + sudo dpkg --configure -a + sudo apt-get install --fix-broken + +### Upgrading Apache 2.2 to 2.4 + +Upgrading from Debian 7 to 8 moves Apache from version 2.2 to 2.4. This version change can break existing websites if you're already running Apache and requires adjusting configuration files. See our [Upgrading Apache](/docs/security/upgrading/updating-virtual-host-settings-from-apache-2-2-to-apache-2-4/) guide for more information. \ No newline at end of file diff --git a/docs/security/upgrading/upgrade-debian-to-the-newest-release/keep-current-grub2-configuration.png b/docs/security/upgrading/upgrade-debian-to-the-newest-release/keep-current-grub2-configuration.png new file mode 100644 index 00000000000..fd497da5133 Binary files /dev/null and b/docs/security/upgrading/upgrade-debian-to-the-newest-release/keep-current-grub2-configuration.png differ diff --git a/docs/security/upgrading/upgrade-to-debian-8-jessie/index.md b/docs/security/upgrading/upgrade-to-debian-8-jessie/index.md index 05b16fea618..6b7a14b9655 100644 --- a/docs/security/upgrading/upgrade-to-debian-8-jessie/index.md +++ b/docs/security/upgrading/upgrade-to-debian-8-jessie/index.md @@ -1,4 +1,5 @@ --- +deprecated: true author: name: Alex Fornuto email: docs@linode.com diff --git a/docs/security/visualize-server-security-on-centos-7-with-an-elastic-stack-and-wazuh/index.md b/docs/security/visualize-server-security-on-centos-7-with-an-elastic-stack-and-wazuh/index.md index 464a6208169..fa7c16fdbab 100644 --- a/docs/security/visualize-server-security-on-centos-7-with-an-elastic-stack-and-wazuh/index.md +++ b/docs/security/visualize-server-security-on-centos-7-with-an-elastic-stack-and-wazuh/index.md @@ -7,7 +7,7 @@ og_description: 'An Elastic Stack combines Elasticsearch, Logstash, and Kibana. keywords: ["ossec", "elk stack", "elk,ossec-hids"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' published: 2017-10-17 -modified: 2017-10-17 +modified: 2018-12-11 modified_by: name: Linode title: 'Visualize Server Security on CentOS 7 with an Elastic Stack and Wazuh' @@ -21,7 +21,7 @@ external_resources: ![Visualize Server Security on CentOS 7 with an Elastic Stack and Wazuh](elastic-stack-security-title.jpg "Visualize Server Security on CentOS 7 with an Elastic Stack and Wazuh") -## What are Elasticsearch, ELK Stack, and Wazuh? +## What are Elasticsearch, Elastic Stack, and Wazuh? An Elastic Stack, formerly known as an ELK Stack, is a combination of Elasticsearch, Logstash, and Kibana. In this tutorial, you will learn how to install and link together ElasticSearch, Logstash, Kibana, with Wazuh OSSEC to help monitor and visualize security threats to your machine. The resulting structure can be broken down into three core components that work with Wazuh's endpoint security: @@ -45,14 +45,18 @@ Wazuh is an open source branch of the original [OSSEC HIDS](https://ossec.github 1. Many of the steps in this guide require root privileges. Complete the sections of our [Securing Your Server](/docs/security/securing-your-server/) to create a standard user account, harden SSH access and remove unnecessary network services. Use `sudo` wherever necessary. -2. Your Linode should have at least [4GB of RAM](https://www.linode.com/pricing). While an Elastic Stack will run on less RAM, the Wazuh Manager will crash if RAM is depleted at any time during use. +1. Your Linode should have at least [8GB of RAM](https://www.linode.com/pricing). While an Elastic Stack will run on less RAM, the Wazuh Manager will crash if RAM is depleted at any time during use. -3. Install NGINX or Apache. Visit our guides on how to install a LEMP or LAMP stack for CentOS for help: +1. Add a domain zone, NS record, and A/AAA record for the domain you will use to access your Kibana installation. See the [DNS Manager](/docs/platform/manager/dns-manager-new-manager/#add-a-domain-zone) guide for details. If you will access your Kibana instance via your Linode's IP address, you can skip this step. + +1. [Create an SSL Certificate](https://linode.com/docs/security/ssl/install-lets-encrypt-to-create-ssl-certificates/), if you will be using SSL encryption for your domain. + +1. Install NGINX or Apache. Visit our guides on how to install a LEMP or LAMP stack for CentOS for help: - [Install a LEMP Stack on CentOS 7 with FastCGI](/docs/web-servers/lemp/lemp-stack-on-centos-7-with-fastcgi/) - [LAMP on CentOS 7](/docs/web-servers/lamp/lamp-on-centos-7/) -4. Configure your webserver for virtual domain hosting: +1. Configure your webserver for virtual domain hosting: **NGINX** @@ -62,27 +66,29 @@ Wazuh is an open source branch of the original [OSSEC HIDS](https://ossec.github - [Apache Configuration Basics](/docs/web-servers/apache-tips-and-tricks/apache-configuration-basics/) -## Update System and Install Pre-requisites +## Update System and Install Prerequisites 1. Update system packages: yum update -y && yum upgrade -y -2. Install Java 8 JDK: +1. Install Java 8 JDK: yum install java-1.8.0-openjdk.x86_64 -3. Verify the Java installation by checking the version: +1. Verify the Java installation by checking the version: java -version Your output should be similar to: - openjdk version "1.8.0_144" - OpenJDK Runtime Environment (IcedTea 3.5.1) (suse-13.3-x86_64) - OpenJDK 64-Bit Server VM (build 25.144-b01, mixed mode) + {{< output >}} + openjdk version "1.8.0_191" + OpenJDK Runtime Environment (build 1.8.0_191-b12) + OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode) + {{}} -3. Install curl: +1. If your Linode doesn't have curl installed, install curl: yum install curl @@ -96,28 +102,34 @@ gpgcheck=1 gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH enabled=1 name=CentOS-$releasever - Wazuh -baseurl=https://packages.wazuh.com/yum/el/$releasever/$basearch +baseurl=https://packages.wazuh.com/3.x/yum/ protect=1 {{< /file >}} -2. Install Wazuh Manager: +1. Install Wazuh Manager: yum install wazuh-manager -3. Install Wazuh API: +1. Install Wazuh API: 1. Install the Node.js repository: - curl --silent --location https://rpm.nodesource.com/setup_6.x | bash - + curl --silent --location https://rpm.nodesource.com/setup_8.x | bash - - 2. Install NodeJS: + 1. Install NodeJS: - yum install nodejs + yum install -y nodejs - 3. Install Wazuh API: + 1. Install Wazuh API: yum install wazuh-api + {{< note >}} + Python >= 2.7 is required in order to run the Wazuh API. To find out which version of Python is running on your Linode, issue the following command: + + python --version + {{}} + ## Install Elasticsearch, Logstash, and Kibana Install the Elastic Stack via RPM files to get the latest versions of all the software. Be sure to check the [Elastic website](https://www.elastic.co/downloads) for more recent software versions. Adjust the commands below to match. @@ -127,69 +139,70 @@ Install the Elastic Stack via RPM files to get the latest versions of all the so 1. Download the Elasticsearch RPM into the `/opt` directory: cd /opt - curl https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.2.rpm + curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.2.rpm -2. Install Elasticsearch: +1. Install Elasticsearch: - rpm -ivh elasticsearch-5.5.2.rpm + rpm -i elasticsearch-6.5.2.rpm -3. Enable the Elasticsearch service to start on system boot: +1. Enable the Elasticsearch service to start on system boot: systemctl enable elasticsearch systemctl start elasticsearch -4. Load the Wazuh Elasticsearch template. Replace `exampleIP` with your Linode's public IP address: +1. Verify that Elasticsearch has installed and is listening on port 9200: + + curl "http://localhost:9200/?pretty" + + You should receive a similar response: + + {{< output >}} + { + "name" : "-7B24Uk", + "cluster_name" : "elasticsearch", + "cluster_uuid" : "UdLfdUOoRH2elGYckoiewQ", + "version" : { +   "number" : "6.5.2", +    "build_flavor" : "default", +   "build_type" : "rpm", +   "build_hash" : "9434bed", +   "build_date" : "2018-11-29T23:58:20.891072Z", +   "build_snapshot" : false, +   "lucene_version" : "7.5.0", +   "minimum_wire_compatibility_version" : "5.6.0", +   "minimum_index_compatibility_version" : "5.0.0" +   }, + "tagline" : "You Know, for Search" +} + {{}} + +1. Load the Wazuh Elasticsearch template. Replace `exampleIP` with your Linode's public IP address: + + curl https://raw.githubusercontent.com/wazuh/wazuh/3.7/extensions/elasticsearch/wazuh-elastic6-template-alerts.json | curl -X PUT "http://exampleIP:9200/_template/wazuh" -H 'Content-Type: application/json' -d @- - curl https://raw.githubusercontent.com/wazuh/wazuh-kibana-app/master/server/startup/integration_files/template_file.json | curl -XPUT 'http://exampleIP:9200/_template/wazuh' -H 'Content-Type: application/json' -d @- ### Install Logstash 1. Download the Logstash RPM into the `/opt` directory: cd /opt - curl https://artifacts.elastic.co/downloads/logstash/logstash-5.5.2.rpm + curl -L -O https://artifacts.elastic.co/downloads/logstash/logstash-6.5.2.rpm -2. Install Logstash: +1. Install Logstash: - rpm -ivh logstash-5.5.2.rpm + rpm -i logstash-6.5.2.rpm -3. Enable Logstash on system boot: +1. Enable Logstash on system boot: systemctl daemon-reload systemctl enable logstash systemctl start logstash -4. Download the Wazuh config and template files for Logstash: +1. Download the Wazuh config file for a **single-host architecture** for Logstash: curl -so /etc/logstash/conf.d/01-wazuh.conf https://raw.githubusercontent.com/wazuh/wazuh/2.0/extensions/logstash/01-wazuh.conf - curl -so /etc/logstash/wazuh-elastic5-template.json https://raw.githubusercontent.com/wazuh/wazuh/2.0/extensions/elasticsearch/wazuh-elastic5-template.json - -5. Modify the `01-wazuh.conf` file to indicate a single-host architecture. Replicate the contents below into your own file. The changes consist of commenting out the `Remote Wazuh Manager` section and uncommenting the `Local Wazuh Manager` section: - - {{< file "/etc/logstash/conf.d/01-wazuh.conf" >}} -# Wazuh - Logstash configuration file -## Remote Wazuh Manager - Filebeat input -#input { -# beats { -# port => 5000 -# codec => "json_lines" -## ssl => true -## ssl_certificate => "/etc/logstash/logstash.crt" -## ssl_key => "/etc/logstash/logstash.key" -# } -#} -# Local Wazuh Manager - JSON file input -input { - file { - type => "wazuh-alerts" - path => "/var/ossec/logs/alerts/alerts.json" - codec => "json" - } -} -. . . -{{< /file >}} -6. Add the Logstash user to the "ossec" group to allow access to restricted files: +1. Add the Logstash user to the `ossec` group to allow access to restricted files: usermod -aG ossec logstash @@ -205,11 +218,11 @@ LS_GROUP=logstash . . . {{< /file >}} -2. Update the service with the new parameters: +1. Update the service with the new parameters: /usr/share/logstash/bin/system-install -3. Restart Logstash: +1. Restart Logstash: systemctl restart logstash @@ -218,35 +231,43 @@ LS_GROUP=logstash 1. Download the Kibana RPM into the `/opt` directory: cd /opt - curl https://artifacts.elastic.co/downloads/kibana/kibana-5.5.2-x86_64.rpm + curl -L -O https://artifacts.elastic.co/downloads/kibana/kibana-6.5.2-x86_64.rpm -2. Install Kibana: +1. Install Kibana: - rpm -ivh kibana-5.5.2-x86_64.rpm + rpm -i kibana-6.5.2-x86_64.rpm -3. Enable Kibana on system boot: +1. Enable Kibana on system boot: systemctl enable kibana systemctl start kibana -4. Install the Wazuh app for Kibana: +1. Install the Wazuh app for Kibana: - /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/wazuhapp/wazuhapp.zip + sudo -u kibana NODE_OPTIONS="--max-old-space-size=3072" /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/wazuhapp/wazuhapp-3.7.1_6.5.2.zip The Kibana app installation process takes several minutes to complete and it may appear as though the process has stalled. -5. If you will access Kibana remotely, configure it to listen on your IP address. Replace the following values with the correct parameters. If you are accessing Kibana from a local host, you can leave the `server.host` value alone. +1. By default Kibana only listens on the loopback interface. To configure it to listen on all interfaces, update the `/etc/kibana/kibana.yml` file and uncomment `server.host` and the following value: + + {{< file "/etc/kibana/kibana.yml">}} +# Specifies the address to which the Kibana server will bind. IP addresses and host names are both valid values. +# The default is 'localhost', which usually means remote machines will not be able to connect. +# To allow connections from remote users, set this parameter to a non-loopback address. +server.host: "0.0.0.0" + {{}} + + Reference the table below for information on other configurations available in the `/etc/kibana/kibana.yml` file: | Value | Parameter | | :-------------: | :----------------------------------------------------------------------------------------: | - | server.port | Change this value if the default port, `5601`, is in use. | - | server.host | Set this value to your Linode's external IP address. | - | server.name | This value is used for display purposes only. Set to anything you wish, or leave it alone. | + | server.port | If the default port `5601` is in use, change this value. | + | server.name | This value is used for display purposes only. Set to anything you wish, or leave it unchanged. | | logging.dest | Specify a location to log program information. `/var/log/kibana.log` is recommended. | You may modify other values in this file as you see fit, but this configuration should work for most. -6. Restart Kibana: +1. Restart Kibana: systemctl restart kibana @@ -254,11 +275,18 @@ LS_GROUP=logstash The Elastic Stack will require some tuning before it can be accessed via the Wazuh API. -1. Enable memory locking in Elasticsearch to mitigate poor performance. Uncomment or add this line to `/etc/elasticsearch/elasticsearch.yml`: +1. Enable memory locking in Elasticsearch to mitigate poor performance. Uncomment the `bootstrap.memory_lock: true` line in the `/etc/elasticsearch/elasticsearch.yml` file: - bootstrap.memory_lock: true + {{< file "/etc/elasticsearch/elasticsearch.yml">}} +# ----------------------------------- Memory ----------------------------------- +# +# Lock the memory on startup: +# +bootstrap.memory_lock: true +# + {{}} -2. Edit locked memory allocation. Follow the instructions under the appropriate init system used in your system: +1. Edit locked memory allocation. Follow the instructions under the appropriate init system used on your Linode: **SystemD** @@ -272,15 +300,15 @@ LimitMEMLOCK=infinity **System V** - Edit the `/etc/sysconfig/elasticsearch` file for RPM or `/etc/default/elasticsearch` for Debian and Ubuntu. Add or change the following line: + Edit the `/etc/sysconfig/elasticsearch` file. Add or change the following line: - {{< file "/etc/sysconfig/elasticsearch or /etc/default/elasticsearch" >}} + {{< file "/etc/sysconfig/elasticsearch" >}} . . . MAX_LOCKED_MEMORY=unlimited . . . {{< /file >}} -3. Configure the Elasticsearch heap size based on your Linode's resources. This figure will determine how much memory Elasticsearch is allowed to consume. Keep the following rules in mind: +1. Configure the Elasticsearch heap size based on your Linode's resources. This figure will determine how much memory Elasticsearch is allowed to consume. Keep the following rules in mind: - No more than 50% of available RAM - No more than 32GB of RAM @@ -300,21 +328,26 @@ MAX_LOCKED_MEMORY=unlimited This configures Elasticsearch with 4GB of allotted RAM. You may also use the `M` letter to specify megabytes, `Xms4096M` in this example. View your current RAM consumption with the `htop` command. If you do not have htop installed, install it with your distribution's package manager. Allocate as much RAM as you can, up to 50% of the max, while leaving enough available for other daemon and system processes. +1. Restart Elasticsearch for the configurations to take effect: + + systemctl daemon-reload + systemctl restart elasticsearch + ## Configure a Reverse Proxy A reverse proxy server allows you to secure the Kibana web interface with SSL and limit access to others. Instructions are provided for NGINX and Apache. The instructions assume you have your webserver configured to host virtual domains. ### Set up a Reverse Proxy Server to Host Kibana as a Subdomain -If you have SSL encryption enabled on your domain, follow the instructions in the **SSL** section. If not, follow the instructions included in the **Non SSL** section. Although you may skip this section if you wish to access Kibana through its server port, this approach is recommended. +If you have SSL encryption enabled on your domain, follow the instructions in the **HTTPS** section below. If not, follow the instructions included in the **HTTP** section. Although you may skip this section if you wish to access Kibana through its server port, this approach is recommended. #### NGINX -1. Navigate to your NGINX virtual host config directory. Create a new virtual host config file and name it something similar to `kibana.conf`. Add the contents below to this file. If you do not have a domain name available, replace the `server_name` parameter value with your Linode's external IP address: +1. Navigate to your NGINX virtual host config directory. Create a new virtual host config file and name it something similar to `example.conf`. Replace `example.com` Add the contents below to this file. If you do not have a domain name available, replace the `server_name` parameter value with your Linode's external IP address: - **Non SSL** + **HTTP** - {{< file "/etc/nginx/conf.d or /etc/nginx/conf" >}} + {{< file "/etc/nginx/conf.d/example.com.conf" >}} server { listen 80; # Remove the line below if you do not have IPv6 enabled. @@ -335,9 +368,9 @@ server { } {{< /file >}} - **SSL** + **HTTPS** - {{< file "/etc/nginx/conf.d or /etc/nginx/conf" >}} + {{< file "/etc/nginx/conf.d/example.com.conf" >}} server { listen 80; # Remove the line below if you do note have IPv6 enabled. @@ -374,17 +407,21 @@ server { ssl_certificate_key /path/to/ssl/certificate.key; auth_basic "Restricted Access"; - auth_basic_user_file /etc/nginx/htpasswd.users; + auth_basic_user_file /etc/nginx/.htpasswd; } {{< /file >}} -2. Secure your Kibana site with a login page. Create a **.htpasswd** file first if you do not have one: +1. Install `httpd-tools` if it is not already installed on your Linode: + + yum install httpd-tools - touch /etc/nginx/htpasswd.users - htpasswd -c /etc/nginx/.htpasswd.users YourNewUsername - chmod 644 /etc/nginx/.htpasswd.users +1. Secure your Kibana site with a login page. Create a **.htpasswd** file first if you do not have one: -3. Restart the NGINX server to load the new configuration: + touch /etc/nginx/.htpasswd + htpasswd -c /etc/nginx/.htpasswd YourNewUsername + chmod 644 /etc/nginx/.htpasswd + +1. Restart the NGINX server to load the new configuration: systemctl restart nginx @@ -399,7 +436,7 @@ server { - proxy_balancer_module - proxy_http_module -2. Enable the necessary mods in Apache. Open `00-proxy.conf` and verify that the lines below are included: +1. Enable the necessary mods in Apache. Open `00-proxy.conf` and verify that the lines below are included: {{< file "/etc/httpd/conf.modules.d/00-proxy.conf" >}} . . . @@ -410,11 +447,11 @@ LoadModule proxy_http_module modules/mod_proxy_http.so . . . {{< /file >}} -3. Create a new virtual config file for the Kibana site. Add the contents below to this file. If you do not have a domain name available, replace the `server_name` parameter value with your Linode's public IP address. Replace `kibana.exampleIPorDomain` and `http://exampleIPorDomain` with your specific values: +1. Create a new virtual config file for the Kibana site. Add the contents below to this file. If you do not have a domain name available, replace the `server_name` parameter value with your Linode's public IP address. Replace `kibana.exampleIPorDomain` and `http://exampleIPorDomain` with your specific values: - **Non SSL** + **HTTP** - {{< file "/etc/httpd/sites-available/kibana.conf or /etc/apache2/sites-available/kibana.conf" >}} + {{< file "/etc/httpd/sites-available/example.com.conf" >}} ServerName kibana.exampleIPorDomain ProxyPreserveHost On @@ -431,9 +468,9 @@ LoadModule proxy_http_module modules/mod_proxy_http.so {{< /file >}} - **SSL** + **HTTPS** - {{< file "/etc/httpd/sites-available/kibana.conf or /etc/apache2/sites-available/kibana.conf" >}} + {{< file "/etc/httpd/sites-available/example.com.conf" >}} ServerName kibana.exampleIPorDomain ProxyPreserveHost On @@ -473,13 +510,13 @@ LoadModule proxy_http_module modules/mod_proxy_http.so {{< /file >}} -4. Secure your Kibana site with a login page. Create a **.htpasswd** file first if you do not have one: +1. Secure your Kibana site with a login page. Create a **.htpasswd** file first if you do not have one: touch /etc/apache2/htpasswd.users htpasswd -c /etc/apache2/.htpasswd.users YourNewUsername chmod 644 /etc/apache2/.htpasswd.users -5. Restart Apache: +1. Restart Apache: systemctl restart httpd @@ -487,7 +524,7 @@ LoadModule proxy_http_module modules/mod_proxy_http.so The new Kibana subdomain will need to be configured in the Linode DNS Manager. -1. Login to the Linode Manager and select your Linode VPS. Click on *DNS Manager*. Add a new A/AAA record for the subdomain. Refer to the table below for the field values. +1. Login to the Linode Manager and select **Domains**. Click on your domain's corresponding ellipses and select **Edit DNS Records**. Add a new A/AAA record for the subdomain. Refer to the table below for the field values. | Field | Value | | :-------------: | :--------------------------------------------------: | @@ -495,41 +532,46 @@ The new Kibana subdomain will need to be configured in the Linode DNS Manager. | IP Address | Set this value to your Linode's external IP address. | | TTL | Set this to 5 minutes. | -2. Click **Save Changes**. +1. Click **Save Changes**. ## Open the Kibana Port -Kibana's default access port, `5601`, must be opened for TCP traffic. Instructions are presented below for UFW, Iptables, and FirewallD. +Kibana's default access port, `5601`, must be opened for TCP traffic. Instructions are presented below for FirewallD, iptables, and UFW. -**UFW** +**FirewallD** - ufw allow 5601/tcp comment "Kibana port" + firewall-cmd --add-port=5601/tcp --permanent + firewall-cmd --reload + +1. Set SELinux to allow HTTP connections: + + setsebool -P httpd_can_network_connect 1 **iptables** iptables -A INPUT -p tcp --dport 5601 -m comment --comment "Kibana port" -j ACCEPT {{< note >}} -To avoid losing iptables rules after a server reboot, save your rules to a file using `iptables-save`, or install iptables-persistent to automatically save rules. +To avoid losing iptables rules after a server reboot, save your rules to a file using `iptables-save`. {{< /note >}} -**FirewallD** +**UFW** - firewall-cmd --add-port=5601/tcp --permanent + ufw allow 5601/tcp comment "Kibana port" ## Connect the Elastic Stack with the Wazuh API -Now you are ready to access the API and begin making use of your OSSEC Elastic Stack! +Now you are ready to access the API and begin making use of your OSSEC Elastic Stack. -1. The Wazuh API requires users to provide credentials in order to login. Navigate to `/var/ossec/api/configuration/auth`. Replace `NewUserName` whatever user name you choose. Set a password following the system prompts: +1. The Wazuh API requires users to provide credentials in order to login. Navigate to `/var/ossec/api/configuration/auth`. Replace `NewUserName` with whatever user name you choose. Set a password following the system prompts: - sudo node htpasswd -c user NewUserName + node htpasswd -c user NewUserName -2. Restart the Wazuh API: +1. Restart the Wazuh API: systemctl restart wazuh-api -3. Check the status of all daemon components and verify that they are running: +1. Check the status of all daemon components and verify that they are running: systemctl -l status wazuh-api systemctl -l status wazuh-manager @@ -542,10 +584,10 @@ Now you are ready to access the API and begin making use of your OSSEC Elastic S If the Wazuh Manager fails to start and you determine the cause to be one of the OSSEC rules or decoders, disable that specific rule/decoder for now. Find the rules and decoders in the `/var/ossec/ruleset` directory. To disable, rename the file to any other file extension. {{< /note >}} -4. In a web browser, navigate to the Kibana homepage. If you created a subdomain for Kibana, the URL will be similar to `kibana.exampleIPorDomain`. You can also reach Kibana by navigating to your server's IP address and specifying port `5601`. Login with the credentials you setup for your Kibana site. +1. In a web browser, navigate to the Kibana homepage. If you created a subdomain for Kibana, the URL will be similar to `kibana.exampleIPorDomain`. You can also reach Kibana by navigating to your server's IP address and specifying port `5601`. Login with the credentials you setup for your Kibana site. -5. If everything is working correctly, you should have landed on the **Discover** page. Navigate to the **Wazuh** page using the left hand side menu. You will be immediately presented with the API configuration page. Underneath the **ADD NEW API** button, enter the user credentials you created for Wazuh. For URL and Port, enter you URL or IP and `55000`, then click **SAVE**. +1. If everything is working correctly, you should have landed on the **Discover** page. Navigate to the **Wazuh** page using the left hand side menu. You will be immediately presented with the API configuration page. Underneath the **ADD NEW API** button, enter the user credentials you created for Wazuh. For URL and Port, enter you URL or IP and `55000`, then click **SAVE**. ## Where To Go From Here -Your OSSEC Elastic Stack setup is now complete! At this point, you will want to customize and configure your OSSEC rules to better suit the needs of your environment. The Wazuh API contains pre-configured charts and queries, and more information on how to use them can be found in the official Wazuh documentation. +Your OSSEC Elastic Stack setup is now complete! At this point, you will want to customize and configure your OSSEC rules to better suit the needs of your environment. The Wazuh API contains pre-configured charts and queries, and more information on how to use them can be found in the official [Wazuh documentation](https://documentation.wazuh.com/current/user-manual/index.html). diff --git a/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/Install_Alpine_Linux_on_your_Linode_smg.png b/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/Install_Alpine_Linux_on_your_Linode_smg.png new file mode 100644 index 00000000000..1e4803c2e16 Binary files /dev/null and b/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/Install_Alpine_Linux_on_your_Linode_smg.png differ diff --git a/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/index.md b/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/index.md index a3ba37cbb23..fc259570170 100644 --- a/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/index.md +++ b/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/index.md @@ -5,7 +5,7 @@ author: description: 'Alpine Linux is a small, security-oriented Linux distro. This guide explains how to install and configure Alpine Linux on a Linode' keywords: ["alpine", "alpine linux", "custom", "custom distro", "install alpine linux", "alpine linux packages"] license: '[CC BY-ND 4.0](http://creativecommons.org/licenses/by-nd/4.0/)' -modified: 2018-01-18 +modified: 2018-12-18 modified_by: name: Linode published: 2016-09-22 @@ -17,6 +17,8 @@ external_resources: - '[Alpine Linux](http://www.alpinelinux.org/)' --- +![Install Alpine Linux on your Linode](Install_Alpine_Linux_on_your_Linode_smg.png "Install Alpine Linux on your Linode") + [Alpine Linux](http://www.alpinelinux.org/) is a small, security-oriented Linux distro. It's regularly updated with security patches, and runs on the [grsecurity](https://grsecurity.net/) kernel. All binaries are statically linked and built against [musl libc](http://www.musl-libc.org/intro.html). diff --git a/docs/web-servers/caddy/install-caddy-archlinux/index.md b/docs/web-servers/caddy/install-caddy-archlinux/index.md new file mode 100644 index 00000000000..a3633e24934 --- /dev/null +++ b/docs/web-servers/caddy/install-caddy-archlinux/index.md @@ -0,0 +1,88 @@ +--- +author: + name: Linode Community + email: docs@linode.com +description: 'Caddy is an open source HTTP/2-enabled web server with automatic HTTPS. This guide demonstrates how to install Caddy on Arch Linux.' +keywords: ['caddy', 'install caddy', 'archlinux', 'web server'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +published: 2018-12-14 +modified: 2018-12-14 +modified_by: + name: Linode +title: "Install Caddy on Arch Linux" +contributor: + name: Claudio Costa + link: https://github.com/streamer45 +external_resources: +- '[Caddy Official Documentation](https://caddyserver.com/docs)' +--- + +## Before You Begin + +1. Familiarize yourself with our [Getting Started](/docs/getting-started) guide and complete the steps for setting your Linode's hostname and timezone. + +1. This guide will use `sudo` wherever possible. Complete the sections of our [Securing Your Server](/docs/security/securing-your-server) guide to create a standard user account, harden SSH access and remove unnecessary network services. + +1. You will need to register your site's domain name and follow our [DNS Manager Overview](/docs/networking/dns/dns-manager-overview#add-records) guide to point your domain to your Linode. + +1. Update your system with `sudo pacman -Syu` + +1. Install the development package group with `sudo pacman -S base-devel` + +## What is Caddy? + +Caddy is an open source HTTP/2 capable web server with automatic HTTPS written in [Go](https://golang.org/). It supports a variety of web site technologies, includes security defaults, and is very easy to use. + +## Install Caddy + +You can install Caddy on Arch Linux by using a snapshot from the *Arch User Repository* (AUR). + +1. Download the snapshot from the AUR: + + curl https://aur.archlinux.org/cgit/aur.git/snapshot/caddy.tar.gz -o caddy.tar.gz + +1. Unpack the snapshot: + + tar xf caddy.tar.gz + +1. Navigate to the `caddy` directory: + + cd caddy + +1. Build and install the package: + + makepkg -si + +## Test Caddy + +1. Start the Caddy web server: + + sudo systemctl start caddy + +1. Enable the Caddy service: + + sudo systemctl enable caddy + +1. Navigate to your Linode's domain name or IP address in a web browser. You should see the Caddy default page displayed. + +## Configure Caddy + +Caddy configuration files reside in `/etc/caddy/` and website configuration files should be created in the `/etc/caddy/caddy.conf.d/` directory. + +1. Create a sample configuration file for your website. Replace `example.com` with your Linode's domain name. If you have not set up a domain, but still want to get started with Caddy, replace `example.com` with `:80`. + + {{< file "/etc/caddy/caddy.conf.d/example.com.conf" caddy >}} +example.com { + root /usr/share/caddy/ +} +{{< /file >}} + + {{< note >}} +If you choose to serve your site from a directory other than `/usr/share/caddy/`, you must remove the Caddy test site files located in that directory. The `/usr/share/caddy/` directory is prioritized over other locations, so any files stored in that directory will be served first, even if you have configured a different directory location. +{{< /note >}} + +1. Reload Caddy: + + sudo systemctl reload caddy + +1. Navigate to your Linode's domain name in a web browser. You should be able to see content served from the root directory configured above. diff --git a/docs/web-servers/nginx/how-to-configure-nginx/index.md b/docs/web-servers/nginx/how-to-configure-nginx/index.md index 5dbdf05530e..bb7b38c0699 100644 --- a/docs/web-servers/nginx/how-to-configure-nginx/index.md +++ b/docs/web-servers/nginx/how-to-configure-nginx/index.md @@ -7,7 +7,7 @@ og_description: 'NGINX is a high-performance web server that delivers large amou keywords: ["nginx", "web server", "configuration"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' aliases: ['web-servers/nginx/configuration/basic/','websites/nginx/basic-nginx-configuration/index.cfm/','websites/nginx/basic-nginx-configuration/','websites/nginx/how-to-configure-nginx/index.cfm/','websites/nginx/how-to-configure-nginx/'] -modified: 2018-03-08 +modified: 2018-12-18 modified_by: name: Linode published: 2010-01-18 @@ -30,7 +30,7 @@ Configuration options in NGINX are called [directives](http://nginx.org/en/docs/ Lines preceded by a `#` character are comments and not interpreted by NGINX. Lines containing directives must end with a `;` or NGINX will fail to load the configuration and report an error. -Below is a condensed copy of the `/etc/nginx/nginx.conf` file that is included with installations from the NGINX repositories. The file starts with 5 directives: `user`, `worker_processes`, `error_log`, and `pid`. These are outside any specific block or context, so they're said to exist in the `main` context. The `events` and `http` blocks are areas for additional directives, and they also exist in the `main` context. +Below is a condensed copy of the `/etc/nginx/nginx.conf` file that is included with installations from the NGINX repositories. The file starts with 4 directives: `user`, `worker_processes`, `error_log`, and `pid`. These are outside any specific block or context, so they're said to exist in the `main` context. The `events` and `http` blocks are areas for additional directives, and they also exist in the `main` context. See [the NGINX docs](https://nginx.org/en/docs/ngx_core_module.html) for explanations of these directives and others available in the `main` context. diff --git a/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/Multiple_WordPress.png b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/Multiple_WordPress.png new file mode 100644 index 00000000000..6d9ddc1b55a Binary files /dev/null and b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/Multiple_WordPress.png differ diff --git a/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/index.md b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/index.md index d87dc1d3568..7d9e85de296 100644 --- a/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/index.md +++ b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/index.md @@ -5,7 +5,8 @@ author: description: 'This guide shows how to configure Apache Virtual Hosts to serve multiple WordPress sites from the same Linode.' keywords: ["install WordPress", "WordPress on Linode", "multiple WordPress", "how to configure WordPress"] license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' -modified: 2017-10-27 +aliases: ['websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/'] +modified: 2018-12-17 modified_by: name: Linode contributor: @@ -16,167 +17,208 @@ external_resources: - '[WordPress.org](http://wordpress.org)' - '[WordPress Codex](http://codex.wordpress.org)' - '[WordPress Support](http://wordpress.org/support)' -- '[Apache Virtual Host documentation](http://httpd.apache.org/docs/current/vhosts/)' +- '[Apache virtual host documentation](http://httpd.apache.org/docs/current/vhosts/)' --- -![WordPress on Apache](Multiple_WordPress.jpg) +![Set Up Apache to Run Multiple WordPress Sites on a Single Linode](Multiple_WordPress.jpg) ## What is WordPress? -WordPress is a popular, dynamic, content management system that makes it easy to build anything from blogs to complete websites and online stores. This guide shows you how to configure your system to run multiple WordPress sites on a single Linode, using Apache Virtual Hosts. +WordPress is a popular, dynamic, content management system that makes it easy to build anything from blogs to complete websites and online stores. This guide shows you how to configure your system to run multiple WordPress sites on a single Linode running Ubuntu 18.04. ## Before You Begin -- Configure a [LAMP](/docs/web-servers/lamp/install-lamp-stack-on-ubuntu-16-04/) web stack. +1. Familiarize yourself with our [Getting Started](/docs/getting-started) guide and complete the steps for setting your Linode’s hostname and timezone. -- This guide assumes you have followed the [Install WordPress on Ubuntu 16.04](/docs/websites/cms/install-wordpress-on-ubuntu-16-04/) guide, and are familiar with the procedures described there. +1. This guide will use sudo wherever possible. Complete the sections of our [Securing Your Server](/docs/security/securing-your-server) guide to create a standard user account, harden SSH access and remove unnecessary network services. -- Make sure MySQL has a database set up for each separate instance of WordPress that you wish to run. If you do not have a WordPress database, create one: +1. If you have not already, [assign Linode's name servers](/docs/platform/manager/dns-manager/#use-linode-s-name-servers-with-your-domain) to your domain at your domain name's registrar. - 1. Log in to the MySQL command line as the root user: +1. Update your system: - mysql -u root -p + apt-get update && apt-get upgrade - 2. Create the WordPress databases with a separate namespace: +## Install a LAMP Stack - CREATE DATABASE example1_wordpress; +WordPress can be deployed on a LAMP stack. A LAMP (Linux, Apache, MySQL, PHP) stack is a common, free, and open source web stack used for hosting web content in a Linux environment. - 3. Create a user and grant them privileges for the newly created `example1_wordpress` database, replacing `example1_wpuser` and `password` with the username and password you wish to use: +Install the LAMP stack using the Tasksel tool: - CREATE USER 'example1_wpuser' IDENTIFIED BY 'password1'; - GRANT ALL PRIVILEGES ON example1_wordpress.* TO 'example1_wpuser'; + sudo tasksel install lamp-server - 4. Repeat Steps 2 and 3 for each instance of WordPress that you want to run, replacing the `example` namespace with a keyword of your choice representing the additional sites: +## Create Your Site Databases and Users - CREATE USER 'example2_wpuser' IDENTIFIED BY 'password2'; - GRANT ALL PRIVILEGES ON example1_wordpress.* TO 'example2_wpuser'; +You will need a MySQL database for *each instance* of WordPress you intend to run. An example of a two-WordPress setup is shown below. Replace `example1` and `example2` with your respective website names. - 5. Exit MySQL: - - quit +| Domain | Database | Username | Password | +| ---------| ---------| ---------| -------- | +| example1.com | example1_wordpress | example1_wpuser | password1 | +| example2.com | example2_wordpress | example2_wpuser | password2 | -- This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you're not familiar with the `sudo` command, you can check our [Users and Groups](/docs/tools-reference/linux-users-and-groups/) guide. +1. Log in to the MySQL command line as the root user: - - All configuration files should be edited with elevated privileges. Remember to include `sudo` before running your text editor. + sudo mysql -u root -An example of a two WordPress setup is: +1. Create the WordPress databases: -| Hostname | Database | Username | Password | -| ---------| ---------| ---------| -------- | -| example1.com | example1_wordpress | example1_wpuser | password1 | -| example2.com | example2_wordpress | example2_wpuser | password2 | + CREATE DATABASE example1_wordpress; + CREATE DATABASE example2_wordpress; -Replace each instance of `example.com`, `example`, `example1`, `example2`, and the other example variables in this guide with your respective site's domain name and namespace keyword. +1. Create the database users, replacing `example1_wpuser` and `password` with a username and password of your own: -## Install Multiple WordPress Instances + CREATE USER 'example1_wpuser' IDENTIFIED BY 'password1'; + CREATE USER 'example2_wpuser' IDENTIFIED BY 'password2'; -The following steps are adapted from the [Install WordPress](/docs/websites/cms/install-wordpress-on-ubuntu-16-04/#install-wordpress) section of the [Install WordPress on Ubuntu 16.04](/docs/websites/cms/install-wordpress-on-ubuntu-16-04/) guide. +1. Grant the users privileges for their respective database: -1. Create the directory that will host your website and WordPress source files. In this guide, the home directory `/var/www/html/example1.com/` is used as an example. Navigate to that new directory: + GRANT ALL PRIVILEGES ON example1_wordpress.* TO 'example1_wpuser'; + GRANT ALL PRIVILEGES ON example1_wordpress.* TO 'example2_wpuser'; - sudo mkdir /var/www/html/example1.com/ - sudo mkdir /var/www/html/example2.com/ - cd /var/www/html/example1.com/ +1. Exit MySQL: -2. Create a directory called `src` under `/var/www/html/example1.com/`. Download and extract the latest version of WordPress: + quit - sudo mkdir /var/www/html/example1.com/src/ - cd /var/www/html/example1.com/src/ - sudo wget http://wordpress.org/latest.tar.gz - tar -zxvf latest.tar.gz +## Install Multiple WordPress Instances -3. Repeat the procedure for `example2.com`: +1. Create the directories that will host your websites and WordPress source files. In this guide, the home directories `/var/www/html/example1.com/` and `/var/www/html/example2.com/` are used as examples. - sudo mkdir /var/www/html/example2.com/src/ - cd /var/www/html/example2.com/src/ - sudo wget http://wordpress.org/latest.tar.gz - sudo tar -zxvf latest.tar.gz + sudo mkdir -p /var/www/html/{example1.com,example2.com}/public_html -4. Rename `latest.tar.gz` as `wordpress` followed by the date to store a backup of the original source files. This will be useful if you install new versions in the future and need to revert back to a previous release: +1. Create a `src` directory to hold the WordPress tarball and files: - sudo mv latest.tar.gz wordpress-`date "+%Y-%m-%d"`.tar.gz + sudo mkdir /var/www/html/src/ - Repeat this step in `/var/www/html/example2.com/src`. +1. Download and extract the latest version of WordPress to the `src` folder: -5. Set your web server's user, `www-data`, as the owner of your site's home directory: + cd /var/www/html/src/ + sudo wget http://wordpress.org/latest.tar.gz - sudo chown -R www-data:www-data /var/www/html/example1.com/ - sudo chown -R www-data:www-data /var/www/html/example2.com/ +1. Extract the tarball. To store a backup of the original source files, rename `latest.tar.gz` to `wordpress` followed by the date. This will be useful if you install new versions in the future and need to revert back to a previous release. -6. Copy the WordPress files to your `public_html` folder: + sudo tar -zxvf latest.tar.gz + sudo mv latest.tar.gz wordpress-`date "+%Y-%m-%d"`.tar.gz - sudo cp -R /var/www/html/example1.com/src/wordpress/* ../public_html/ - sudo cp -R /var/www/html/example2.com/src/wordpress/* ../public_html/ +1. Copy the WordPress files to your site's `public_html` folders: -7. Give your web server ownership of the `public_html` folder: + sudo cp -R /var/www/html/src/wordpress/* /var/www/html/example1.com/public_html/ + sudo cp -R /var/www/html/src/wordpress/* /var/www/html/example2.com/public_html/ - sudo chown -R www-data:www-data /var/www/html/example1.com/public_html - sudo chown -R www-data:www-data /var/www/html/example2.com/public_html +1. Give Apache ownership of your WordPress sites' home directories: -8. Repeat for each additional instance of WordPress that you want to run. + sudo chown -R www-data:www-data /var/www/html/{example1.com,example2.com}/ ## Configure Apache Virtual Hosts -Up until this point, the steps have been fairly straightforward and similar to setting up a single instance of WordPress. In this section, configure Apache Virtual Hosts so that a visitor to `example1.com` will be served the content in `/var/www/html/example1.com/public_html` and backed by the MySQL database `example1_wordpress`. +In this section, you will configure the Apache virtual hosts file so that a visitor to `example1.com` will be served the content in `/var/www/html/example1.com/public_html` and the MySQL database `example1_wordpress`. Visitors to `example2.com` will be served content in `/var/www/html/example2.com/public_html/` and its corresponding MySQL database. -1. Go to the Apache `sites-available` directory: +1. Create a virtual hosts configuration file for `example1.com` and add the example virtual host block into `/etc/apache2/sites-available/example1.com`. Be sure to replace all instances of `example1.com` with your own domain. - cd /etc/apache2/sites-available + {{< file "/etc/apache2/sites-available/example1.conf" apache >}} + + # The primary domain for this host + ServerName example1.com + # Optionally have other subdomains also managed by this Virtual Host + ServerAlias example1.com *.example1.com + DocumentRoot /var/www/html/example1.com/public_html + + Require all granted + # Allow local .htaccess to override Apache configuration settings + AllowOverride all + + # Enable RewriteEngine + RewriteEngine on + RewriteOptions inherit + + # Block .svn, .git + RewriteRule \.(svn|git)(/)?$ - [F] + + # Catchall redirect to www.example1.com + RewriteCond %{HTTP_HOST} !^www.example1\.com [NC] + RewriteCond %{HTTP_HOST} !^$ + RewriteRule ^/(.*) https://www.example1.com/$1 [L,R] + + # Recommended: XSS protection + + Header set X-XSS-Protection "1; mode=block" + Header always append X-Frame-Options SAMEORIGIN + + -2. Copy `000-default.conf` as needed: + {{}} - cp 000-default.conf example1.conf - cp 000-default.conf example2.conf +1. Enable the site. This will create a symlink to the `example1.com` Apache conf file in `/etc/apache2/sites-enabled/`: -3. Put the following contents in `example1.com`: + sudo a2ensite example1.conf - {{< file "example1.conf" apache >}} +1. Create a virtual hosts configuration file for your second WordPress site, `example2.com`. Be sure to replace all instances of `example2.com` with your own domain. + + {{< file "/etc/apache2/sites-available/example2.conf" apache >}} -# The primary domain for this host -ServerName example1.com -# Optionally have other subdomains also managed by this Virtual Host -ServerAlias example1.com *.example1.com -DocumentRoot /var/www/html/example1.com/public_html - -Require all granted -# Allow local .htaccess to override Apache configuration settings -AllowOverride all - -# Enable RewriteEngine -RewriteEngine on -RewriteOptions inherit - -# Block .svn, .git -RewriteRule \.(svn|git)(/)?$ - [F] - -# Catchall redirect to www.example1.com -RewriteCond %{HTTP_HOST} !^www.example1\.com [NC] -RewriteCond %{HTTP_HOST} !^$ -RewriteRule ^/(.*) https://www.example1.com/$1 [L,R] - -# Recommended: XSS protection - -Header set X-XSS-Protection "1; mode=block" -Header always append X-Frame-Options SAMEORIGIN - + # The primary domain for this host + ServerName example2.com + # Optionally have other subdomains also managed by this Virtual Host + ServerAlias example2.com *.example2.com + DocumentRoot /var/www/html/example2.com/public_html + + Require all granted + # Allow local .htaccess to override Apache configuration settings + AllowOverride all + + # Enable RewriteEngine + RewriteEngine on + RewriteOptions inherit + + # Block .svn, .git + RewriteRule \.(svn|git)(/)?$ - [F] + + # Catchall redirect to www.example2.com + RewriteCond %{HTTP_HOST} !^www.example2\.com [NC] + RewriteCond %{HTTP_HOST} !^$ + RewriteRule ^/(.*) https://www.example2.com/$1 [L,R] + + # Recommended: XSS protection + + Header set X-XSS-Protection "1; mode=block" + Header always append X-Frame-Options SAMEORIGIN + + {{}} -{{}} +1. Enable the site: + sudo a2ensite example2.conf -4. Enable the site. This will create a symlink to the `example.com` Apache conf file in `/etc/apache2/sites-enabled/`: + You can repeat Steps 1 and 2 for each WordPress site that you want to host on your Linode. - sudo a2ensite example1.conf +1. If the `rewrite_module` module is not enabled, you will need to enable it before reloading Apache to have your configurations take effect. To check which Apache modules are enabled, run the following command: + + sudo apache2ctl -M -5. Restart Apache to enable the changes: + Verify that you see `rewrite_module` in the list. If you do not see the module, enable it with the following command: - sudo systemctl restart apache2 + sudo a2enmod rewrite -6. Repeat Steps 2 through 5 for each WordPress site that you want to run. +1. For the new configurations to take effect, reload Apache: + + sudo systemctl reload apache2 ## Configure WordPress -Follow the steps from the [Configure WordPress](/docs/websites/cms/install-wordpress-on-ubuntu-16-04/#configure-wordpress) section of the [Install WordPress on Ubuntu 16.04](/docs/websites/cms/install-wordpress-on-ubuntu-16-04/) guide. +Follow the [Configure WordPress](/docs/websites/cms/install-wordpress-ubuntu-18-04/#configure-wordpress) section of our Install WordPress on Ubuntu 18.04 guide. + +If you do not yet have registered domains to use, you can still perform the WordPress installation using your Linode's IP address. For example: + +1. Verify your WordPress installation by using your Linode's IP address to load the WordPress installations in your browser: + + http://203.0.113.15/example1.com/public_html + http://203.0.113.15/example2.com/public_html + + You should see WordPress' set up page: + + ![WordPress setup-config.php](wp-config.png) + +1. You can begin configuring your WordPress sites. Follow the [Configure WordPress](/docs/websites/cms/install-wordpress-ubuntu-18-04/#configure-wordpress) section of our Install WordPress on Ubuntu 18.04 guide. +1. If you have not yet added DNS records for your Domains, follow the *Add DNS Records* steps in the [Host a Website on Ubuntu 18.04](/docs/websites/hosting-a-website-ubuntu-18-04/#add-dns-records) guide. diff --git a/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/wordpress-setup-config-php.png b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/wordpress-setup-config-php.png new file mode 100644 index 00000000000..6174b3f9f56 Binary files /dev/null and b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/wordpress-setup-config-php.png differ diff --git a/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/wp-config.png b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/wp-config.png new file mode 100644 index 00000000000..f5fbf917775 Binary files /dev/null and b/docs/websites/cms/configure-apache-to-run-multiple-wordpress-sites-on-one-linode/wp-config.png differ diff --git a/docs/websites/hosting-a-website-ubuntu-18-04/index.md b/docs/websites/hosting-a-website-ubuntu-18-04/index.md index 988aa35ebc4..380a969dd5a 100644 --- a/docs/websites/hosting-a-website-ubuntu-18-04/index.md +++ b/docs/websites/hosting-a-website-ubuntu-18-04/index.md @@ -318,6 +318,10 @@ It's a good idea to test your website(s) before you add the DNS records. This is 1. Enter your Linode's IP address in a web browser (e.g., type `http://192.0.2.0` in the address bar, replacing the example IP address with your own). Your website should load in the web browser. + {{< note >}} + If you have configured a firewall on your Linode, ensure your firewall rules allow traffic to your Apache web server. For more information on configuring firewall rules on Ubuntu, see [How to Configure a Firewall with UFW](/docs/security/firewalls/configure-firewall-with-ufw/). + {{}} + 1. If you plan on hosting multiple websites, you can test the virtual hosts by editing the `hosts` file on your local computer. Check out the [Previewing Websites Without DNS](/docs/networking/dns/previewing-websites-without-dns/) guide for more information. 1. Test the name-based virtual hosts by entering the domain names in the address bar of the web browser on a local device. Your websites should load in the web browser. diff --git a/themes/docsmith/layouts/_default/list.html b/themes/docsmith/layouts/_default/list.html index d77312bb992..46c51b036ea 100644 --- a/themes/docsmith/layouts/_default/list.html +++ b/themes/docsmith/layouts/_default/list.html @@ -10,7 +10,11 @@
+ {{ if and (eq .Kind "taxonomy") (eq .Data.Singular "audience") }} +

{{ .Title }} Guides

+ {{ else }}

{{ .Title }}

+ {{ end }}

{{ .Description | markdownify }}

diff --git a/themes/docsmith/layouts/_default/terms.html b/themes/docsmith/layouts/_default/terms.html new file mode 100644 index 00000000000..d77312bb992 --- /dev/null +++ b/themes/docsmith/layouts/_default/terms.html @@ -0,0 +1,20 @@ +{{ define "main" }} +
+
+
+
+ {{ partial "breadcrumb" . }} +
+ +
+
+

{{ .Title }}

+

{{ .Description | markdownify }}

+
+
+ +
+{{ partial "articles_and_categories" . }} +{{ end }} diff --git a/themes/docsmith/layouts/partials/cloud_manager_link.html b/themes/docsmith/layouts/partials/cloud_manager_link.html index 58a3cf47cce..31806290f9c 100644 --- a/themes/docsmith/layouts/partials/cloud_manager_link.html +++ b/themes/docsmith/layouts/partials/cloud_manager_link.html @@ -1,6 +1,9 @@ {{ with .Params.cloud_manager_link }} {{ end }} + + +