[Yandex Cloud documentation](../../../../index.md) > [Yandex Application Load Balancer](../../../index.md) > [Tutorials](../../index.md) > [Migrating services from NLB to L7 ALB for enabling Smart Web Security protection](../index.md) > [NLB as a target for ALB](index.md) > Terraform

# Migrating services from an external NLB to an L7 ALB with an internal NLB as a target using Terraform

# Migrating services from an external NLB to an L7 ALB with an internal NLB as a target using Terraform


To migrate a service from a network load balancer to an L7 load balancer:

1. [See the service migration recommendations](#recommendations).
1. [Create an internal network load balancer for the NGINX Ingress Controller](#create-internal-nlb).
1. [Create the infrastructure](#deploy). At this step, you will associate the Smart Web Security profile with a virtual host of the L7 load balancer.
1. [Test the L7 load balancer](#test).
1. [Migrate user traffic from the network load balancer to the L7 load balancer](#migration-nlb-to-alb).

## Service migration recommendations {#recommendations}

1. Optionally, enable L3-L4 DDoS protection ([the OSI model](https://en.wikipedia.org/wiki/OSI_model)). It will enhance the L7 protection provided by [Yandex Smart Web Security](../../../../smartwebsecurity/index.md) after migration.

    To enable L3-L4 protection:

    1. Before the migration, [reserve a public static IP address with DDoS protection](../../../../vpc/operations/enable-ddos-protection.md#enable-on-reservation) and use this address for the L7 load balancer's listener. If you already have a protected public IP address for the load balancer, you can keep this address during migration. Otherwise, you will have to change the IP address to a protected one.

    1. Configure a trigger threshold for the protection mechanisms, consistent with the amount of legitimate traffic to the protected resource. To set up this threshold, contact [support](https://center.yandex.cloud/support).

    1. [Set](../../../../vpc/operations/adjust-mtu-ddos-protection.md) the MTU value to `1450` for the targets downstream of the load balancer. For more information, see [MTU and TCP MSS](../../../../vpc/concepts/mtu-mss.md).

1. Perform migration during the hours when the user load is at its lowest. If you decided to keep your public IP address, your service will be unavailable during the migration while this IP address is moved from the load balancer to the L7 load balancer. This usually takes a few minutes.

1. When using an L7 load balancer, requests to backends come with the source IP address from the range of internal IP addresses of the subnets specified when creating the L7 load balancer. The original IP address of the request source (user) is specified in the `X-Forwarded-For` header. If you want to log public IP addresses of users on the web server, reconfigure it.

1. Before the migration, define the minimum number of resource units for the [autoscaling](../../../concepts/application-load-balancer.md#lcu-scaling) settings in the L7 load balancer:

    Select the number of resource units based on the analysis of your service load expressed in:

    * Number of requests per second (RPS).
    * Number of concurrent active connections.
    * Number of new connections per second.
    * Traffic processed per second.

## Create an internal network load balancer for the NGINX Ingress Controller {#create-internal-nlb}

1. Create an internal network load balancer for the NGINX Ingress controller. Select an option that agrees with the method you initially used to deploy your NGINX Ingress controller:

    {% list tabs %}

    * Using a Helm chart

        1. Add the configuration parameters for the internal network load balancer to the `values.yaml` file you used to initially configure the NGINX Ingress controller. Leave the other parameters in the file unchanged.

            ```bash
            controller:
              service:
                external:
                  enabled: true
                internal:
                  enabled: true
                  annotations:
                    yandex.cloud/load-balancer-type: internal
                    yandex.cloud/subnet-id: <subnet_ID_for_internal_network_load_balancer_IP_address>
                  loadBalancerIP: <IP_address_of_internal_network_load_balancer_listener>
                  externalTrafficPolicy: Local
            ```

        1. Use this command to apply the NGINX Ingress controller configuration changes:

            ```bash
            helm upgrade <NGINX_Ingress_controller_name> -f values.yaml <chart_for_NGINX_Ingress_controller> -n <namespace>
            ```

    * Using a manifest

        1. Create a YAML file and describe the `Service` resource in it:

            ```bash
            apiVersion: v1
            kind: Service
            metadata:
              name: <resource_name>
              namespace: <namespace>
              annotations:
                yandex.cloud/load-balancer-type: internal
                yandex.cloud/subnet-id: <subnet_ID_for_internal_network_load_balancer_IP_address>
            spec:
              type: LoadBalancer
              externalTrafficPolicy: Local
              loadBalancerIP: <IP_address_of_internal_network_load_balancer_listener>
              ports:
              - port: <80_or_another_port_number_for_HTTP>
                targetPort: <80_or_another_port_number_for_NGINX_Ingress_controller_pod_for_HTTP>
                protocol: TCP
                name: http
              - port: <443_or_another_port_number_for_HTTPS>
                targetPort: <443_or_another_port_number_for_NGINX_Ingress_controller_pod_for_HTTPS>
                protocol: TCP
                name: https
              selector:
                <NGINX_Ingress_controller_pod_selectors>
            ```

        1. Apply the changes using this command:

        ```bash
        kubectl apply -f <Service_resource_file>
        ```

    {% endlist %}

1. Wait until the internal network load balancer is created and a matching `Service` object appears. You can use this command to view information about the services:

    ```bash
    kubectl get service
    ```

## Create an infrastructure for the L7 load balancer {#deploy}

1. If you do not have Terraform yet, [install it](../../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform).
1. [Get the authentication credentials](../../../../tutorials/infrastructure-management/terraform-quickstart.md#get-credentials). You can add them to environment variables or specify them later in the provider configuration file.
1. [Configure and initialize a provider](../../../../tutorials/infrastructure-management/terraform-quickstart.md#configure-provider). There is no need to create a provider configuration file manually, you can [download it](https://github.com/yandex-cloud-examples/yc-terraform-provider-settings/blob/main/provider.tf).
1. Place the configuration file in a separate working directory and [specify the parameter values](../../../../tutorials/infrastructure-management/terraform-quickstart.md#configure-provider). If you did not add the authentication credentials to environment variables, specify them in the configuration file.

1. Download the configuration file to the same working directory based on the protocol you are using:
    * `HTTP`: [alb-int-nlb-http.tf](https://github.com/yandex-cloud-examples/yc-nlb-alb-internal-lb-migration/blob/main/alb-int-nlb-http.tf) configuration file
    * `HTTPS`: [alb-int-nlb-https.tf](https://github.com/yandex-cloud-examples/yc-nlb-alb-internal-lb-migration/blob/main/alb-int-nlb-https.tf) configuration file

    These files describe:

    * [Subnets](../../../../vpc/concepts/network.md#subnet) for the L7 load balancer.
    * [Security group](../../../../vpc/concepts/security-groups.md) for the L7 load balancer.
    * Static address for the L7 load balancer.
    * Importing a TLS certificate to Certificate Manager (if using `HTTPS`).
    * Smart Web Security profile.
    * Target group, backend group, and HTTP router for the L7 load balancer.
    * L7 load balancer.

1. Specify the following variables in the configuration file:

    * `domain_name`: Your service domain name.
    * `network_id`: ID of the network containing the VMs from the network load balancer's target group.
    * `ip_address_int_nlb`: Internal IP address of the internal load balancer you [created earlier](#create-internal-nlb).
    * `certificate` (for `HTTPS`): Path to the self-signed custom certificate.
    * `private_key` (for `HTTPS`): Path to the private key file.

1. Make sure the Terraform configuration files are correct using this command:

    ```bash
    terraform validate
    ```

    Terraform will display any configuration errors detected in your files.

1. Create the required infrastructure:

    1. Run this command to view the planned changes:
    
       ```bash
       terraform plan
       ```
    
       If you described the configuration correctly, the terminal will display a list of the resources to update and their parameters. This is a verification step that does not apply changes to your resources.
    
    1. If everything looks correct, apply the changes:
       1. Run this command:
    
          ```bash
          terraform apply
          ```
    
       1. Confirm updating the resources.
       1. Wait for the operation to complete.

    All the required resources will be created in the specified folder. You can check resource availability and their settings in the [management console](https://console.yandex.cloud).

1. In the management console, select the folder where you created the L7 load balancer.
1. Navigate to **Application Load Balancer**.
1. Wait until the L7 load balancer goes `Active`.
1. Specify the autoscaling settings in the L7 load balancer:

    1. In the management console, click the load balancer's name.
    1. Click ![image](../../../../_assets/console-icons/ellipsis.svg) and select **Edit**.
    1. Under **Autoscaling settings**, set the [resource unit](../../../concepts/application-load-balancer.md#lcu-scaling) limit.
    1. Click **Save**.

## Test the L7 load balancer {#test}

1. In the [management console](https://console.yandex.cloud), navigate to the new L7 load balancer and select **Health checks** on the left. Make sure you get `HEALTHY` for all the L7 load balancer's health checks.

1. Run a test request to the service through the L7 load balancer, for example, using one of these methods:
   
   * Add this record to the `hosts` file on your workstation: `<L7_load_balancer_public_IP_address> <service_domain_name>`. Delete the record after the test.
   * Execute the request using [cURL](https://curl.se/) depending on the protocol type:
   
       ```bash
       curl http://<service_domain_name> \
           --resolve <service_domain_name>:<service_port>:<public_IP_address_of_L7_load_balancer>
       ```
   
       ```bash
       curl https://<service_domain_name> \
           --resolve <service_domain_name>:<service_port>:<public_IP_address_of_L7_load_balancer>
       ```

## Migrate user traffic from the external network load balancer to the L7 load balancer {#migration-nlb-to-alb}

Select one of these migration options:

* [Keep the public IP address for your service](#save-public-ip).
* [Do not keep the public IP address for your service](#not-save-public-ip).

### Keep the public IP address for your service {#save-public-ip}

1. If your external network load balancer is using a dynamic public IP address, [convert it to a static one](../../../../vpc/operations/set-static-ip.md).

1. Delete the external network load balancer. Select an option that agrees with the method you initially used to deploy your NGINX Ingress Controller:

    {% list tabs %}

    * Using a Helm chart

        1. In the `values.yaml` file you used to initially configure the NGINX Ingress Controller, under `controller.service.external`, set `enabled: false`. Leave the other parameters in the file unchanged.

            ```bash
            controller:
              service:
                external:
                  enabled: false
                ...
            ```

        1. Use this command to apply the configuration changes for the NGINX Ingress Controller:

            ```bash
            helm upgrade <NGINX_Ingress_Controller_name> -f values.yaml <chart_for_NGINX_Ingress_Controller> -n <namespace>
            ```

    * Using a manifest

        Delete the `Service` resource for the external network load balancer using this command:

        ```bash
        kubectl delete service <name_of_Service_resource_for_external_network_load_balancer>
        ```

    {% endlist %}

1. Wait until the external network load balancer for the NGINX Ingress Controller and its respective `Service` object are deleted. You can use this command to view information about the services:

    ```bash
    kubectl get service
    ```

    This will make your service unavailable through the external network load balancer.

1. In the L7 load balancer, assign to the listener the public IP address previously assigned to the external network load balancer.

    1. Open the configuration file you used to create the L7 load balancer (`alb-int-nlb-http.tf` or `alb-int-nlb-https.tf`).

    1. In the load balancer description, update the `address` parameter under `listener.endpoint.address.external_ipv4_address`:

        ```hcl
        resource "yandex_alb_load_balancer" "<load_balancer_name>" {
          ...
          listener {
            ...
            endpoint {
              address {
                external_ipv4_address {
                  address = <service_public_IP_address>
                }
              }
              ports = [ <service_port> ]
            }
          }
        }
        ```

        Where `address` is the public IP address the network load balancer used previously.

    1. Apply the changes:

        1. In the terminal, navigate to the configuration file directory.
        1. Make sure the configuration is correct using this command:
        
           ```bash
           terraform validate
           ```
        
           If the configuration is valid, you will get this message:
        
           ```bash
           Success! The configuration is valid.
           ```
        
        1. Run this command:
        
           ```bash
           terraform plan
           ```
        
           You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
        1. Apply the configuration changes:
        
           ```bash
           terraform apply
           ```
        
        1. Type `yes` and press **Enter** to confirm the changes.

1. After the IP address changes, your service will again be available through the L7 load balancer. Monitor the L7 load balancer's user traffic on the [load balancer statistics](../../../operations/application-load-balancer-get-stats.md) charts.

1. Delete the now free static public IP address you selected when creating the L7 load balancer.

    1. Open the configuration file you used to create the L7 load balancer (`alb-int-nlb-http.tf` or `alb-int-nlb-https.tf`).

    1. Delete the `yandex_vpc_address` resource description from the file:

        ```hcl
        resource "yandex_vpc_address" "static-address" {
          description = "Static public IP address for the Application Load Balancer"
          name        = "alb-static-address"
          external_ipv4_address {
            zone_id                  = "ru-central1-a"
            ddos_protection_provider = "qrator"
          }
        }
        ```

    1. Apply the changes:

        1. In the terminal, navigate to the configuration file directory.
        1. Make sure the configuration is correct using this command:
        
           ```bash
           terraform validate
           ```
        
           If the configuration is valid, you will get this message:
        
           ```bash
           Success! The configuration is valid.
           ```
        
        1. Run this command:
        
           ```bash
           terraform plan
           ```
        
           You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
        1. Apply the configuration changes:
        
           ```bash
           terraform apply
           ```
        
        1. Type `yes` and press **Enter** to confirm the changes.

### Do not keep the public IP address for your service {#not-save-public-ip}

1. To migrate user traffic from an external network load balancer to an L7 load balancer, in the DNS service of your domain's public zone, update the `A` record value for the service domain name to point to the L7 load balancer's public IP address. If the public domain zone was created in [Yandex Cloud DNS](../../../../dns/index.md), update the record using [this guide](../../../../dns/operations/resource-record-update.md).

    {% note info %}

    The migration may take a while because the propagation of DNS record's updates depends on its time-to-live (TTL) and the number of links in the DNS request chain.

    {% endnote %}

1. As the DNS record updates propagate, monitor the increase in requests to the L7 load balancer on the [load balancer statistics](../../../operations/application-load-balancer-get-stats.md) charts.

1. Monitor the decrease in traffic on the external network load balancer using the `processed_bytes` and `processed_packets` [load balancer metrics](../../../../monitoring/metrics-ref/network-load-balancer-ref.md). You can [create a dashboard](../../../../monitoring/operations/dashboard/create.md) to visualize these metrics. If there is no load on the network load balancer for a long time, the migration to the L7 load balancer is complete.

1. Optionally, once migration is complete, [delete the external network load balancer](../../../../network-load-balancer/operations/load-balancer-delete.md). Select an option that agrees with the method you initially used to deploy your NGINX Ingress Controller:

    {% list tabs %}

    * Using a Helm chart

        1. In the `values.yaml` file you used to initially configure the NGINX Ingress Controller, under `controller.service.external`, set `enabled: false`. Leave the other parameters in the file unchanged.

            ```bash
            controller:
              service:
                external:
                  enabled: false
                ...
            ```

        1. Use this command to apply the configuration changes for the NGINX Ingress Controller:

            ```bash
            helm upgrade <NGINX_Ingress_Controller_name> -f values.yaml <chart_for_NGINX_Ingress_Controller> -n <namespace>
            ```

        {% note warning %}

        When you update the NGINX Ingress Controller configuration, your service will be temporarily unavailable.

        {% endnote %}

    * Using a manifest

        Delete the `Service` resource for the external network load balancer using this command:

        ```bash
        kubectl delete service <name_of_Service_resource_for_external_network_load_balancer>
        ```

    {% endlist %}

1. Optionally, wait until the external network load balancer for the NGINX Ingress Controller and its respective `Service` object are deleted. You can use this command to view information about the services:

    ```bash
    kubectl get service
    ```