

# AWS IoT secure tunneling
<a name="secure-tunneling"></a>

When devices are deployed behind restricted firewalls at remote sites, you need a way to gain access to those devices for troubleshooting, configuration updates, and other operational tasks. Use secure tunneling to establish bidirectional communication to remote devices over a secure connection that is managed by AWS IoT. Secure tunneling does not require updates to your existing inbound firewall rules, so you can keep the same security level provided by firewall rules at a remote site.

For example, a sensor device located at a factory that is a couple hundred miles away is having trouble measuring the factory temperature. You can use secure tunneling to open and quickly start a session to that sensor device. After you have identified the problem (for example, a bad configuration file), you can reset the file and restart the sensor device through the same session. Compared to a more traditional troubleshooting (for example, sending a technician to the factory to investigate the sensor device), secure tunneling decreases incident response and recovery time and operational costs.

# What is secure tunneling?
<a name="secure-tunneling-what-is"></a>

Use secure tunneling to access devices that are deployed behind port-restricted firewalls at remote sites. You can connect to the destination device from your laptop or desktop computer as the source device by using the AWS Cloud. The source and destination communicate by using an open source local proxy that runs on each device. The local proxy communicates with the AWS Cloud by using an open port that is allowed by firewall, typically 443. Data that is transmitted through the tunnel is encrypted using Transported Layer Security (TLS).

**Topics**
+ [

# Secure tunneling concepts
](secure-tunneling-concepts.md)
+ [

# How secure tunneling works
](how-secure-tunneling-works.md)
+ [

# Secure tunnel lifecycle
](tunnel-lifecycle.md)

# Secure tunneling concepts
<a name="secure-tunneling-concepts"></a>

The following terms are used by secure tunneling when establishing communication with remote devices. For information about how secure tunneling works, see [How secure tunneling works](how-secure-tunneling-works.md).

**Client access token (CAT)**  
A pair of tokens generated by secure tunneling when a new tunnel is created. The CAT is used by the source and destination devices to connect to the secure tunneling service. The CAT can only be used once to connect to the tunnel. To reconnect to the tunnel, rotate the client access tokens using the [RotateTunnelAccessToken](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_RotateTunnelAccessToken.html) API operation or the [rotate-tunnel-access-token](https://docs.aws.amazon.com/cli/latest/reference/iotsecuretunneling/rotate-tunnel-access-token.html) CLI command.

**Client token**  
A unique value generated by the client that AWS IoT secure tunneling can use for all subsequent retry connections to the same tunnel. This field is optional. If the client token is not provided, then the client access token (CAT) can only be used once for the same tunnel. Subsequent connection attempts using the same CAT will be rejected. For more information about using client tokens, see the [ local proxy reference implementation in GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy/blob/master/V2WebSocketProtocolGuide.md).

**Destination application**  
The application that runs on the destination device. For example, the destination application can be an SSH daemon for establishing an SSH session using secure tunneling.

**Destination device**  
The remote device you want to access.

**Device agent**  
An IoT application that connects to the AWS IoT device gateway and listens for new tunnel notifications over MQTT. For more information, see [IoT agent snippet](configure-remote-device.md#agent-snippet).

**Local proxy**  
A software proxy that runs on the source and destination devices and relays a data stream between secure tunneling and the device application. The local proxy can be run in source mode or destination mode. For more information, see [Local proxy](local-proxy.md).

**Source device**  
The device an operator uses to initiate a session to the destination device, usually a laptop or desktop computer.

**Tunnel**  
 A logical pathway through AWS IoT that enables bidirectional communication between a source device and destination device.

# How secure tunneling works
<a name="how-secure-tunneling-works"></a>

The following shows how secure tunneling establishes a connection between your source and destination device. For information about the different terms such as client access token (CAT), see [Secure tunneling concepts](secure-tunneling-concepts.md).

1. 

**Open a tunnel**  
To open a tunnel for initiating a session with your remote destination device, you can use the AWS Management Console, the [AWS CLI open-tunnel](https://docs.aws.amazon.com/cli/latest/reference/iotsecuretunneling/open-tunnel.html) command, or the [OpenTunnel API](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_OpenTunnel).

1. 

**Download the client access token pair**  
After you've opened a tunnel, you can download the client access token (CAT) for your source and destination and save it on your source device. You must retrieve the CAT and save it now before starting the local proxy.

1. 

**Start local proxy in destination mode**  
The IoT agent that has been installed and is running on your destination device will be subscribed to the reserved MQTT topic `$aws/things/thing-name/tunnels/notify` and will receive the CAT. Here, *thing-name* is the name of the AWS IoT thing you create for your destination. For more information, see [Secure tunneling topics](reserved-topics.md#reserved-topics-secure).

   The IoT agent then uses the CAT to start the local proxy in destination mode and set up a connection on the destination side of the tunnel. For more information, see [IoT agent snippet](configure-remote-device.md#agent-snippet).

1. 

**Start local proxy in source mode**  
After the tunnel has been opened, AWS IoT Device Management provides the CAT for the source that you can download on the source device. You can use the CAT to start the local proxy in source mode, which then connects the source side of the tunnel. For more information about local proxy, see [Local proxy](local-proxy.md).

1. 

**Open an SSH session**  
As both sides of the tunnel are connected, you can start an SSH session by using the local proxy on the source side.

For more information about how to use the AWS Management Console to open a tunnel and start an SSH session, see [Open a tunnel and start SSH session to remote device](secure-tunneling-tutorial-open-tunnel.md).

 The following video describes how secure tunneling works and walks you through the process of setting up an SSH session to a Raspberry Pi device.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/Vq67jKZTR-c/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/Vq67jKZTR-c)


# Secure tunnel lifecycle
<a name="tunnel-lifecycle"></a>

Tunnels can have the status `OPEN` or `CLOSED`. Connections to the tunnel can have the status `CONNECTED` or `DISCONNECTED`. The following shows how the different tunnel and connection statuses work.

1. When you open a tunnel, it has a status of `OPEN`. The tunnel's source and destination connection status is set to `DISCONNECTED`.

1. When a device (source or destination) connects to the tunnel, the corresponding connection status changes to `CONNECTED`.

1. When a device disconnects from the tunnel while the tunnel status remains `OPEN`, the corresponding connection status changes back to `DISCONNECTED`. A device can connect to and disconnect from a tunnel repeatedly as long as the tunnel remains `OPEN`.
**Note**  
The client access tokens (CAT) can only be used once to connect to a tunnel. To reconnect to the tunnel, rotate the client access tokens using the [RotateTunnelAccessToken](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_RotateTunnelAccessToken.html) API operation or the [rotate-tunnel-access-token](https://docs.aws.amazon.com/cli/latest/reference/iotsecuretunneling/rotate-tunnel-access-token.html) CLI command. For examples, see [Resolving AWS IoT secure tunneling connectivity issues by rotating client access tokens](iot-secure-tunneling-troubleshooting.md).

1. When you call `CloseTunnel` or the tunnel remains `OPEN` for longer than the `MaxLifetimeTimeout` value, a tunnel's status becomes `CLOSED`. You can configure `MaxLifetimeTimeout` when calling `OpenTunnel`. `MaxLifetimeTimeout` defaults to 12 hours if you do not specify a value.
**Note**  
A tunnel cannot be reopened when it is `CLOSED`.

1. You can call `DescribeTunnel` and `ListTunnels` to view tunnel metadata while the tunnel is visible. The tunnel can be visible in the AWS IoT console for at least three hours before it is deleted. 

# AWS IoT secure tunneling tutorials
<a name="secure-tunneling-tutorial"></a>

AWS IoT secure tunneling helps customers establish bidirectional communication to remote devices that are behind a firewall over a secure connection managed by AWS IoT.

To demo AWS IoT secure tunneling, use our [AWS IoT secure tunneling demo on GitHub](https://github.com/aws-samples/iot-secure-tunneling-demo).

The following tutorials will help you learn how to get started and use secure tunneling. You'll learn how to:

1. Create a secure tunnel using the quick setup and manual setup methods for accessing the remote device.

1. Configure the local proxy when using the manual setup method and connect to the tunnel to access the destination device.

1. SSH into the remote device from a browser without having to configure the local proxy.

1. Convert a tunnel created using the AWS CLI or using the manual setup method to use the quick setup method.

## Tutorials in this section
<a name="tunneling-tutorial-overview"></a>

The tutorials in this section focus on creating a tunnel using the AWS Management Console and the AWS IoT API Reference. In the AWS IoT console, you can create a tunnel from the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels) page or from the details page of a thing that you created. For more information, see [Tunnel creation methods in AWS IoT console](secure-tunneling-tutorial-open-tunnel.md#tunneling-tutorial-flows).

Following shows the tutorials in this section:
+ 

**[Open a tunnel and use browser-based SSH to access remote device](tunneling-tutorial-quick-setup.md)**  
This tutorial shows how to open a tunnel from the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels) page using the quick setup method. You'll also learn how to use browser-based SSH to access the remote device using an in-context command line interface within the AWS IoT console.

  
+ 

**[Open a tunnel using manual setup and connect to remote device](tunneling-tutorial-manual-setup.md)**  
This tutorial shows how to open a tunnel from the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels) page using the manual setup method. You'll also learn how to configure and start the local proxy from a terminal in your source device and connect to the tunnel.
+ 

**[Open a tunnel for remote device and use browser-based SSH](tunneling-tutorial-existing-tunnel.md)**  
This tutorial shows how to open a tunnel from the details page of a thing that you created. You'll learn how to create a new tunnel and use an existing tunnel. The existing tunnel corresponds to the most recent, open tunnel that was created for the device. You can also use the browser-based SSH to access the remote device.

**Topics**
+ [

## Tutorials in this section
](#tunneling-tutorial-overview)
+ [

# Open a tunnel and start SSH session to remote device
](secure-tunneling-tutorial-open-tunnel.md)
+ [

# Open a tunnel for remote device and use browser-based SSH
](tunneling-tutorial-existing-tunnel.md)

# Open a tunnel and start SSH session to remote device
<a name="secure-tunneling-tutorial-open-tunnel"></a>

In these tutorials, you'll learn how to remotely access a device that's behind a firewall. You can't start a direct SSH session into the device because the firewall blocks all inbound traffic. The tutorials show you how you can open a tunnel and then use that tunnel to start an SSH session to a remote device.

## Prerequisites for the tutorials
<a name="tunneling-tutorial-prerequisites"></a>

The prerequisites for running the tutorial can vary depending on whether you use the manual or quick setup methods for opening a tunnel and accessing the remote device. 

**Note**  
For both setup methods, you must allow outbound traffic on port 443. 
+ For information about prerequisites for the quick setup method tutorial, see [Prerequisites for quick setup method](tunneling-tutorial-quick-setup.md#tunneling-tutorial-quick-prerequisites).
+ For information about prerequisites for the manual setup method tutorial, see [Prerequisites for manual setup method](tunneling-tutorial-manual-setup.md#tunneling-tutorial-manual-prerequisites). If you use this setup method, you must configure the local proxy on your source device. To download the local proxy source code, see [Local proxy reference implementation on GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy).

## Tunnel setup methods
<a name="tunneling-tutorial-setup-methods"></a>

In these tutorials, you'll learn about the manual and quick setup methods for opening a tunnel and connecting to the remote device. The following table shows the difference between the setup methods. After you create the tunnel, you can use an in-browser command line interface to SSH into the remote device. If you misplace the tokens or the tunnel gets disconnected, you can send new access tokens to reconnect to the tunnel.


**Quick and manual setup methods**  

| Criteria | Quick setup | Manual setup | 
| --- | --- | --- | 
| Tunnel creation | Create a new tunnel with default, editable configurations. To access your remote device, you can only use SSH as the destination service. | Create a tunnel by manually specifying the tunnel configurations. You can use this method to connect to the remote device using services other than SSH. | 
| Access tokens | The destination access token will be automatically delivered to your device on the [reserved MQTT topic](https://docs.aws.amazon.com/iot/latest/developerguide/reserved-topics.html#reserved-topics-secure), if a thing name is specified when creating the tunnel. You don't have to download or manage the token on your source device. | You'll have to manually download and manage the token on your source device. The destination access token is automatically delivered to the remote device on the [reserved MQTT topic](https://docs.aws.amazon.com/iot/latest/developerguide/reserved-topics.html#reserved-topics-secure), if a thing name is specified when creating the tunnel.  | 
| Local proxy | A web-based local proxy is automatically configured for you for interacting with the device. You don't have to manually configure the local proxy. | You'll have to manually configure and launch the local proxy. To configure the local proxy, you can either use the AWS IoT Device Client or download the [Local proxy reference implementation on GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy). | 

## Tunnel creation methods in AWS IoT console
<a name="tunneling-tutorial-flows"></a>

The tutorials in this section show you how to create a tunnel using the AWS Management Console and the [OpenTunnel](https://docs.aws.amazon.com/iot/latest/apireference/) API. If you configure the destination when creating a tunnel, AWS IoT secure tunneling delivers the destination client access token to the remote device over MQTT and the reserved MQTT topic, `$aws/things/RemoteDeviceA/tunnels/notify`). On receiving the MQTT message, the IoT agent on the remote device starts the local proxy in destination mode. For more information, see [Reserved topics](reserved-topics.md).

**Note**  
You can omit the destination configuration if you want to deliver the destination client access token to the remote device through another method. For more information, see [Configuring a remote device and using IoT agent](configure-remote-device.md).

In the AWS IoT console, you can create a tunnel using either of the following methods. For information about tutorials that will help you learn to create a tunnel using these methods, see [Tutorials in this section](secure-tunneling-tutorial.md#tunneling-tutorial-overview).
+ 

**[Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels)**  
When you create the tunnel, you'll be able to specify whether to use the quick setup or the manual setup methods for creating the tunnel and provide the optional tunnel configuration details. The configuration details also include the name of the destination device and the service that you want to use for connecting to the device. After you create a tunnel, you can either SSH within the browser or open a terminal outside the AWS IoT console to access your remote device.
+ 

**Thing details page**  
When you create the tunnel, you'll also be able to specify whether to use the most recent, open tunnel or create a new tunnel for the device, in addition to choosing the setup methods and providing any optional tunnel configuration details. You can't edit the configuration details of an existing tunnel. You can use the quick setup method to rotate the access tokens and SSH into the remote device within the browser. To open a tunnel using this method, you must have created an IoT thing (for example, `RemoteDeviceA`) in the AWS IoT registry. For more information, see [Register a device in the AWS IoT registry](https://docs.aws.amazon.com/iot/latest/developerguide/register-device.html). 

**Topics**
+ [

## Prerequisites for the tutorials
](#tunneling-tutorial-prerequisites)
+ [

## Tunnel setup methods
](#tunneling-tutorial-setup-methods)
+ [

## Tunnel creation methods in AWS IoT console
](#tunneling-tutorial-flows)
+ [

# Open a tunnel and use browser-based SSH to access remote device
](tunneling-tutorial-quick-setup.md)
+ [

# Open a tunnel using manual setup and connect to remote device
](tunneling-tutorial-manual-setup.md)

# Open a tunnel and use browser-based SSH to access remote device
<a name="tunneling-tutorial-quick-setup"></a>

You can use the quick setup or the manual setup method for creating a tunnel. This tutorial shows how to open a tunnel using the quick setup method and use the browser-based SSH to connect to the remote device. For an example that shows how to open a tunnel using the manual setup method, see [Open a tunnel using manual setup and connect to remote device](tunneling-tutorial-manual-setup.md).

Using the quick setup method, you can create a new tunnel with default configurations that can be edited. A web-based local proxy is configured for you and the access token is automatically delivered to your remote destination device using MQTT. After creating a tunnel, you can start interacting with your remote device using a command line interface within the console.

With the quick setup method, you must use SSH as the destination service to access the remote device. For more information about the different setup methods, see [Tunnel setup methods](secure-tunneling-tutorial-open-tunnel.md#tunneling-tutorial-setup-methods).

## Prerequisites for quick setup method
<a name="tunneling-tutorial-quick-prerequisites"></a>
+ The firewalls that the remote device is behind must allow outbound traffic on port 443. The tunnel that you create will use this port to connect to the remote device.
+ You have an IoT device agent (see [IoT agent snippet](configure-remote-device.md#agent-snippet)) running on the remote device that connects to the AWS IoT device gateway and is configured with an MQTT topic subscription. For more information, see [connect a device to the AWS IoT device gateway](https://docs.aws.amazon.com/iot/latest/developerguide/sdk-tutorials.html).
+ You must have an SSH daemon running on the remote device.

## Open a tunnel
<a name="open-tunnel-quick"></a>

You can open a secure tunnel using the AWS Management Console, the AWS IoT API Reference, or the AWS CLI. You can optionally configure a destination name but it's not required for this tutorial. If you configure the destination, secure tunneling will automatically deliver the access token to the remote device using MQTT. For more information, see [Tunnel creation methods in AWS IoT console](secure-tunneling-tutorial-open-tunnel.md#tunneling-tutorial-flows).

**To open a tunnel using the console**

1. Go to the [Tunnels hub of the AWS IoT console](https://console.aws.amazon.com/iot/home#/tunnels) and choose **Create tunnel**.  
![\[AWS IoT console showing an empty list of tunnels with options to create, close, or delete tunnels.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnels-page.png)

1. For this tutorial, choose **Quick setup** as the tunnel creation method and then choose **Next**.
**Note**  
If you create a secure tunnel from the details page of a thing you created, you can choose whether to create a new tunnel or use an existing one. For more information, see [Open a tunnel for remote device and use browser-based SSH](tunneling-tutorial-existing-tunnel.md).  
![\[Setup method section with options for quick setup using SSH or manual setup, explaining the quick setup automatically configures proxy and access token.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnels-choose-quick.PNG)

1. Review and confirm the tunnel configuration details. To create a tunnel, choose **Confirm and create**. If you want to edit these details, choose **Previous** to go back to the previous page and then confirm and create the tunnel.
**Note**  
When using quick setup, the service name can't be edited. You must use **SSH** as the **Service**.

1. To create the tunnel, choose **Done**. 

   For this tutorial, you don't have to download the source or destination access tokens. These tokens can only be used once to connect to the tunnel. If your tunnel gets disconnected, you can generate and send new tokens to your remote device for reconnecting to the tunnel. For more information, see [Resend tunnel access tokens](tunneling-tutorial-manual-setup.md#resend-access-tokens).  
![\[A dialog showing source and destination access tokens for creating a secure tunnel connection, with instructions on rotating and resending tokens if needed.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-success.png)

**To open a tunnel using the API**  
To open a new tunnel, you can use the [OpenTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_OpenTunnel.html) API operation.

**Note**  
You can create a tunnel using the quick setup method only from the AWS IoT console. When you use the AWS IoT API Reference API or the AWS CLI, it will use the manual setup method. You can open the existing tunnel that you created and then change the setup method of the tunnel to use the quick setup. For more information, see [Open an existing tunnel and use browser-based SSH](tunneling-tutorial-existing-tunnel.md#tunneling-tutorial-existing-convert-tunnel).

The following shows an example of how to run this API operation. Optionally, if you want to specify the thing name and the destination service, use the `DestinationConfig` parameter. For an example that shows how to use this parameter, see [Open a new tunnel for the remote device](tunneling-tutorial-existing-tunnel.md#tunneling-tutorial-existing-open-tunnel).

```
aws iotsecuretunneling open-tunnel
```

Running this command creates a new tunnel and provides you the source and destination access tokens. 

```
{
    "tunnelId": "01234567-89ab-0123-4c56-789a01234bcd",
    "tunnelArn": "arn:aws:iot:us-east-1:123456789012:tunnel/01234567-89ab-0123-4c56-789a01234bcd",
    "sourceAccessToken": "<SOURCE_ACCESS_TOKEN>",
    "destinationAccessToken": "<DESTINATION_ACCESS_TOKEN>"
}
```

## Using the browser-based SSH
<a name="tunneling-tutorial-quick-browser"></a>

After you create a tunnel using the quick setup method, and your destination device has connected to the tunnel, you can access the remote device using a browser-based SSH. Using the browser-based SSH, you can directly communicate with the remote device by entering commands into an in-context command line interface within the console. This feature makes it easier for you to interact with the remote device because you don't have to open a terminal outside the console or configure the local proxy. 

**To use the browser-based SSH**

1. Go to the [Tunnels hub of the AWS IoT console](https://console.aws.amazon.com/iot/home#/tunnels) and choose the tunnel that you created to view its details.

1. Expand the **Secure Shell (SSH)** section and then choose **Connect**.

1. Choose whether you want to authenticate into the SSH connection by providing your username and password, or, for more secure authentication, you can use your device's private key. If you're authenticating using the private key, note that only PEM formatted (256 and 512) RSA keys work with AWS IoT Secure Tunneling SSH console. 
   + To connect using your username and password, choose **Use password**. You can then enter your username and password and start using the in-browser CLI.
   + To connect using your destination device's private key, choose **Use private key**. Specify your username and upload the device's private key file, and then choose **Connect** to start using the in-browser CLI.  
![\[Form dialog box to connect via browser CLI with private key, showing a username field and an option to choose or use a pre-selected private key file.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-browser-private-key.png)

After you've authenticated into the SSH connection, you can quickly get started with entering commands and interact with the device using the browser CLI, as the local proxy has already been configured for you.

![\[Code snippet showing React hooks for managing state and preferences in a JavaScript application.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-browser-cli.PNG)


If the browser CLI stays open after the tunnel duration, it might time out, causing the command line interface to get disconnected. You can duplicate the tunnel and start another session to interact with the remote device within the console itself.

## Troubleshooting issues when using the browser-based SSH
<a name="tunneling-tutorial-browser-troubleshoot"></a>

The following shows how to troubleshoot some issues that you might run into when using the browser-based SSH.
+ 

**You see an error instead of the command line interface**  
You might be seeing the error because your destination device got disconnected. You can choose **Generate new access tokens** to generate new access tokens and send the tokens to your remote device using MQTT. The new tokens can be used to reconnect to the tunnel. Reconnecting to the tunnel clears the history and refreshes the command line session.
+ 

**You see a tunnel disconnected error when authenticating using private key**  
You might be seeing the error because your private key might not have been accepted by the destination device. To troubleshoot this error, check the private key file that you uploaded for authentication. If you still see an error, check your device logs. You can also try reconnecting to the tunnel by sending new access tokens to your remote device.
+ 

**Your tunnel was closed when using the session**  
If your tunnel was closed because it stayed open for more than the specified duration, your command line session might get disconnected. A tunnel cannot be reopened once closed. To reconnect, you must open another tunnel to the device.

  You can duplicate a tunnel to create a new tunnel with the same configurations as the closed tunnel. You can duplicate a closed tunnel from the AWS IoT console. To duplicate the tunnel, choose the tunnel that was closed to view its details, and then choose **Duplicate tunnel**. Specify the tunnel duration that you want to use and then create the new tunnel.

## Cleaning up
<a name="tunnel-cleanup-quick"></a>
+ 

**Close tunnel**  
We recommend that you close the tunnel after you've finished using it. A tunnel can also become closed if it stayed open for longer than the specified tunnel duration. A tunnel cannot be reopened once closed. You can still duplicate a tunnel by choosing the closed tunnel and then choosing **Duplicate tunnel**. Specify the tunnel duration that you want to use and then create the new tunnel.
  + To close an individual tunnel or multiple tunnels from the AWS IoT console, go to the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels), choose the tunnels that you want to close, and then choose **Close tunnel**.
  + To close an individual tunnel or multiple tunnels using the AWS IoT API Reference API, use the [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html) API.

    ```
    aws iotsecuretunneling close-tunnel \ 
        --tunnel-id "01234567-89ab-0123-4c56-789a01234bcd"
    ```
+ 

**Delete tunnel**  
You can delete a tunnel permanently from your AWS account. 
**Warning**  
Deletion actions are permanent and can't be undone.
  + To delete an individual tunnel or multiple tunnels from the AWS IoT console, go to the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels), choose the tunnels that you want to delete, and then choose **Delete tunnel**.
  + To delete an individual tunnel or multiple tunnels using the AWS IoT API Reference API, use the [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html) API. When using the API, set the `delete` flag to `true`.

    ```
    aws iotsecuretunneling close-tunnel \ 
        --tunnel-id "01234567-89ab-0123-4c56-789a01234bcd"
        --delete true
    ```

# Open a tunnel using manual setup and connect to remote device
<a name="tunneling-tutorial-manual-setup"></a>

When you open a tunnel, you can choose the quick setup or the manual setup method for opening a tunnel into the remote device. This tutorial shows how to open a tunnel using the manual setup method and configure and start the local proxy to connect to the remote device.

When you use the manual setup method, you must manually specify the tunnel configurations when creating the tunnel. After creating the tunnel, you can SSH within the browser or open a terminal outside the AWS IoT console. This tutorial shows how to use the terminal outside the console to access the remote device. You'll also learn how to configure the local proxy and then connect to the local proxy to interact with the remote device. To connect to the local proxy, you must download the source access token when creating the tunnel.

With this setup method, you can use services other than SSH, such as FTP to connect to the remote device. For more information about the different setup methods, see [Tunnel setup methods](secure-tunneling-tutorial-open-tunnel.md#tunneling-tutorial-setup-methods).

## Prerequisites for manual setup method
<a name="tunneling-tutorial-manual-prerequisites"></a>
+ The firewalls that the remote device is behind must allow outbound traffic on port 443. The tunnel that you create will use this port to connect to the remote device.
+ You have an IoT device agent (see [IoT agent snippet](configure-remote-device.md#agent-snippet)) running on the remote device that connects to the AWS IoT device gateway and is configured with an MQTT topic subscription. For more information, see [connect a device to the AWS IoT device gateway](https://docs.aws.amazon.com/iot/latest/developerguide/sdk-tutorials.html).
+ You must have an SSH daemon running on the remote device.
+ You have downloaded the local proxy source code from [GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy) and built it for the platform of your choice. We'll refer to the built local proxy executable file as `localproxy` in this tutorial.

## Open a tunnel
<a name="open-tunnel"></a>

You can open a secure tunnel using the AWS Management Console, the AWS IoT API Reference, or the AWS CLI. You can optionally configure a destination name but it's not required for this tutorial. If you configure the destination, secure tunneling will automatically deliver the access token to the remote device using MQTT. For more information, see [Tunnel creation methods in AWS IoT console](secure-tunneling-tutorial-open-tunnel.md#tunneling-tutorial-flows).

**To open a tunnel in the console**

1. Go to the [Tunnels hub of the AWS IoT console](https://console.aws.amazon.com/iot/home#/tunnelhub) and choose **Create tunnel**.  
![\[AWS IoT console showing an empty list of tunnels with options to create, close, or delete tunnels.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnels-page.png)

1. For this tutorial, choose **Manual setup** as the tunnel creation method and then choose **Next**. For information about using the **quick setup** method to create a tunnel, see [Open a tunnel and use browser-based SSH to access remote device](tunneling-tutorial-quick-setup.md).
**Note**  
If you create a secure tunnel from the details page of a thing, you can choose whether to create a new tunnel or use an existing one. For more information, see [Open a tunnel for remote device and use browser-based SSH](tunneling-tutorial-existing-tunnel.md).  
![\[Two options for setting up a tunnel connection: Quick setup (SSH) or Manual setup, which requires configuring a local proxy and managing access tokens.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnels-choose-manual.PNG)

1. (Optional) Enter the configuration settings for your tunnel. You can also skip this step and proceed to the next step to create a tunnel. 

   Enter a tunnel description, a tunnel timeout duration, and resource tags as key-value pairs to help you identify your resource. For this tutorial, you can skip the destination configuration.
**Note**  
You won't be charged based on the duration for which you keep a tunnel open. You only incur charges when creating a new tunnel. For pricing information, see **Secure Tunneling** in [AWS IoT Device Management pricing](https://aws.amazon.com/iot-device-management/pricing/).

1. Download the client access tokens and then choose **Done**. The tokens will not be available to download after you choose **Done**.

   These tokens can only be used once to connect to the tunnel. If you misplace the tokens or the tunnel gets disconnected, you can generate and send new tokens to your remote device for reconnecting to the tunnel.  
![\[Source and destination access tokens for creating a secure tunnel connection, with instructions on rotating and resending tokens if needed.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-success.png)

**To open a tunnel using the API**  
To open a new tunnel, you can use the [OpenTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_OpenTunnel.html) API operation. You can also specify additional configurations using the API, such as the tunnel duration and the destination configuration.

```
aws iotsecuretunneling open-tunnel \ 
    --region us-east-1 \ 
    --endpoint https://api.us-east-1.tunneling.iot.amazonaws.com
```

Running this command creates a new tunnel and provides you the source and destination access tokens. 

```
{
    "tunnelId": "01234567-89ab-0123-4c56-789a01234bcd",
    "tunnelArn": "arn:aws:iot:us-east-1:123456789012:tunnel/01234567-89ab-0123-4c56-789a01234bcd",
    "sourceAccessToken": "<SOURCE_ACCESS_TOKEN>",
    "destinationAccessToken": "<DESTINATION_ACCESS_TOKEN>"
}
```

## Resend tunnel access tokens
<a name="resend-access-tokens"></a>

The tokens that you obtained when creating a tunnel can only be used once to connect to the tunnel. If you misplace the access token or the tunnel gets disconnected, you can resend new access tokens to the remote device using MQTT at no additional charge. AWS IoT secure tunneling will revoke the current tokens and return new access tokens for reconnecting to the tunnel.

**To rotate the tokens from the console**

1. Go to the [Tunnels hub of the AWS IoT console](https://console.aws.amazon.com/iot/home#/tunnels) and choose the tunnel that you created.

1. In the tunnel details page, choose **Generate new access tokens** and then choose **Next**.

1. Download the new access tokens for your tunnel and choose **Done**. These tokens can be used only once. If you misplace these tokens or the tunnel gets disconnected, you can resend new access tokens.  
![\[Access tokens for source and destination devices with options to copy or download them. Text explains that rotating tokens revokes current tokens and generates new single-use tokens for reconnecting a disconnected tunnel.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-token-rotated.PNG)

**To rotate access tokens using the API**  
To rotate the tunnel access tokens, you can use the [RotateTunnelAccessToken](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_RotateTunnelAccessToken.html) API operation to revoke the current tokens and return new access tokens for reconnecting to the tunnel. For example, the following command rotates the access tokens for the destination device, *`RemoteThing1`*. 

```
aws iotsecuretunneling rotate-tunnel-access-token \ 
    --tunnel-id <tunnel-id> \ 
    --client-mode DESTINATION \ 
    --destination-config thingName=<RemoteThing1>,services=SSH \ 
    --region <region>
```

Running this command generates the new access token as shown in the following example. The token is then delivered to the device using MQTT to connect to the tunnel, if the device agent is set up correctly.

```
{
    "destinationAccessToken": "destination-access-token", 
    "tunnelArn": "arn:aws:iot:region:account-id:tunnel/tunnel-id"
}
```

For examples that show how and when to rotate the access tokens, see [Resolving AWS IoT secure tunneling connectivity issues by rotating client access tokens](iot-secure-tunneling-troubleshooting.md).

## Configure and start the local proxy
<a name="start-local-proxy"></a>

To connect to the remote device, open a terminal on your laptop and configure and start the local proxy. The local proxy transmits data sent by the application running on the source device by using secure tunneling over a WebSocket secure connection. You can download the local proxy source from [GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy).

After you configure the local proxy, copy the source client access token, and use it to start the local proxy in source mode. Following shows an example command to start the local proxy. In the following command, the local proxy is configured to listen for new connections on port 5555. In this command:
+ `-r` specifies the AWS Region, which must be the same Region where your tunnel was created.
+ `-s` specifies the port to which the proxy should connect.
+ `-t` specifies the client token text.

```
./localproxy -r us-east-1 -s 5555 -t source-client-access-token
```

Running this command will start the local proxy in source mode. If you receive the following error after running the command, set up the CA path. For information, see [Secure tunneling local proxy on GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy).

```
Could not perform SSL handshake with proxy server: certificate verify failed
```

The following shows a sample output of running the local proxy in `source` mode.

```
...
...

Starting proxy in source mode
Attempting to establish web socket connection with endpoint wss://data.tunneling.iot.us-east-1.amazonaws.com:443
Resolved proxy  server IP: 10.10.0.11
Connected successfully with proxy server
Performing SSL handshake with proxy server	
Successfully completed SSL handshake with proxy server
HTTP/1.1 101 Switching Protocols

...

Connection: upgrade
channel-id: 01234567890abc23-00001234-0005678a-b1234c5de677a001-2bc3d456
upgrade: websocket

...

Web socket session ID: 01234567890abc23-00001234-0005678a-b1234c5de677a001-2bc3d456
Web socket subprotocol selected: aws.iot.securetunneling-2.0
Successfully established websocket connection with proxy server: wss://data.tunneling.iot.us-east-1.amazonaws.com:443
Setting up web socket pings for every 5000 milliseconds
Scheduled next read:

...

Starting web socket read loop continue reading...
Resolved bind IP: 127.0.0.1
Listening for new connection on port 5555
```

## Start an SSH session
<a name="start-ssh-session"></a>

Open another terminal and use the following command to start a new SSH session by connecting to the local proxy on port 5555.

```
ssh username@localhost -p 5555
```

You might be prompted for a password for the SSH session. When you are done with the SSH session, type **exit** to close the session.

## Cleaning up
<a name="tunnel-cleanup-manual"></a>
+ 

**Close tunnel**  
We recommend that you close the tunnel after you've finished using it. A tunnel can also become closed if it stayed open for longer than the specified tunnel duration. A tunnel cannot be reopened once closed. You can still duplicate a tunnel by opening the closed tunnel and then choosing **Duplicate tunnel**. Specify the tunnel duration that you want to use and then create the new tunnel.
  + To close an individual tunnel or multiple tunnels from the AWS IoT console, go to the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels), choose the tunnels that you want to close, and then choose **Close tunnel**.
  + To close an individual tunnel or multiple tunnels using the AWS IoT API Reference API, use the [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html) API operation.

    ```
    aws iotsecuretunneling close-tunnel \ 
        --tunnel-id "01234567-89ab-0123-4c56-789a01234bcd"
    ```
+ 

**Delete tunnel**  
You can delete a tunnel permanently from your AWS account.
**Warning**  
Deletion actions are permanent and can't be undone.
  + To delete an individual tunnel or multiple tunnels from the AWS IoT console, go to the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels), choose the tunnels that you want to delete, and then choose **Delete tunnel**.
  + To delete an individual tunnel or multiple tunnels using the AWS IoT API Reference API, use the [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html) API operation. When using the API, set the `delete` flag to `true`.

    ```
    aws iotsecuretunneling close-tunnel \ 
        --tunnel-id "01234567-89ab-0123-4c56-789a01234bcd"
        --delete true
    ```

# Open a tunnel for remote device and use browser-based SSH
<a name="tunneling-tutorial-existing-tunnel"></a>

From the AWS IoT console, you can create a tunnel either from the **Tunnels hub** or from the details page of an IoT thing that you created. When you create a tunnel from the **Tunnels** hub, you can specify whether to create a tunnel using the quick setup or the manual setup. For an example tutorial, see [Open a tunnel and start SSH session to remote device](secure-tunneling-tutorial-open-tunnel.md).

When you create a tunnel from the thing details page of the AWS IoT console, you can also specify whether to create a new tunnel or open an existing tunnel for that thing as illustrated in this tutorial. If you choose an existing tunnel, you can access the most recent, open tunnel that you created for this device. You can then use the command line interface within the terminal to SSH into the device. 

## Prerequisites
<a name="tunneling-tutorial-existing-prerequisites"></a>
+ The firewalls that the remote device is behind must allow outbound traffic on port 443. The tunnel that you create will use this port to connect to the remote device.
+ You have created an IoT thing (for example, `RemoteDevice1`) in the AWS IoT registry. This thing corresponds to the representation of your remote device in the cloud. For more information, see [ Register a device in the AWS IoT registry](https://docs.aws.amazon.com/iot/latest/developerguide/register-device.html).
+ You have an IoT device agent (see [IoT agent snippet](configure-remote-device.md#agent-snippet)) running on the remote device that connects to the AWS IoT device gateway and is configured with an MQTT topic subscription. For more information, see [connect a device to the AWS IoT device gateway](https://docs.aws.amazon.com/iot/latest/developerguide/sdk-tutorials.html).
+ You must have an SSH daemon running on the remote device.

## Open a new tunnel for the remote device
<a name="tunneling-tutorial-existing-open-tunnel"></a>

Say you want to open a tunnel into your remote device, `RemoteDevice1`. First, create an IoT thing with the name `RemoteDevice1` in the AWS IoT registry. You can then create a tunnel using the AWS Management Console, the AWS IoT API Reference API, or the AWS CLI. 

By configuring a destination when creating a tunnel, the secure tunneling service delivers the destination client access token to the remote device over MQTT and the reserved MQTT topic (`$aws/things/RemoteDeviceA/tunnels/notify`). For more information, see [Tunnel creation methods in AWS IoT console](secure-tunneling-tutorial-open-tunnel.md#tunneling-tutorial-flows).

**To create a tunnel for remote device from console**

1. Choose the thing, `RemoteDevice1`, to view its details, and then choose **Create secure tunnel**.  
![\[Details of a device named "RemoteDevice1" with its Amazon Resource Name (ARN) displayed.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-create-thing.PNG)

1. Choose whether to create a new tunnel or open an existing tunnel. To create a new tunnel, choose **Create new tunnel**. You can then choose whether to use the manual setup or the quick setup method to create the tunnel. For more information, see [Open a tunnel using manual setup and connect to remote device](tunneling-tutorial-manual-setup.md) and [Open a tunnel and use browser-based SSH to access remote device](tunneling-tutorial-quick-setup.md).

**To create a tunnel for remote device using API**  
To open a new tunnel, you can use the [OpenTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_OpenTunnel.html) API operation. The following code shows an example of running this command.

```
aws iotsecuretunneling open-tunnel \ 
    --region us-east-1 \ 
    --endpoint https://api.us-east-1.tunneling.iot.amazonaws.com
    --cli-input-json file://input.json
```

Following shows the contents for the `input.json` file. You can use the `destinationConfig` parameter to specify the name of the destination device (for example, `RemoteDevice1`) and the service that you want to use to access the destination device, such as `SSH`. Optionally, you can also specify additional parameters such as tunnel description and tags.

**Contents of input.json**

```
{
   "description": "Tunnel to remote device1",
   "destinationConfig": { 
      "services": [ "SSH" ],
      "thingName": "RemoteDevice1"
   }
}
```

Running this command creates a new tunnel and provides you the source and destination access tokens. 

```
{
    "tunnelId": "01234567-89ab-0123-4c56-789a01234bcd",
    "tunnelArn": "arn:aws:iot:us-east-1:123456789012:tunnel/01234567-89ab-0123-4c56-789a01234bcd",
    "sourceAccessToken": "<SOURCE_ACCESS_TOKEN>",
    "destinationAccessToken": "<DESTINATION_ACCESS_TOKEN>"
}
```

## Open an existing tunnel and use browser-based SSH
<a name="tunneling-tutorial-existing-convert-tunnel"></a>

Say you created the tunnel for your remote device, `RemoteDevice1`, using the manual setup method or using the AWS IoT API Reference API. You can then open the existing tunnel for the device and choose **Quick setup** to use the browser-based SSH feature. The configurations of an existing tunnel can't be edited so you can't use the manual setup method.

To use the browser-based SSH feature, you won't have to download the source access token or configure the local proxy. A web-based local proxy will be automatically configured for you so you can start interacting with your remote device.

**To use the quick setup method and browser-based SSH**

1. Go to the details page of the thing that you created, `RemoteDevice1`, and **Create secure tunnel**.

1. Choose **Use existing tunnel** to open the most recent, open tunnel that you created for the remote device. The tunnel configurations can't be edited so you can't use the manual setup method for the tunnel. To use the quick setup method, choose **Quick setup**.

1. Proceed to review and confirm the tunnel configuration details and create the tunnel. The tunnel configurations can't be edited.

   When you create the tunnel, secure tunneling will use the [RotateTunnelAccessToken](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_RotateTunnelAccessToken.html) API operation to revoke the original access tokens and generate new access tokens. If your remote device uses MQTT, these tokens will be automatically delivered to the remote device on the MQTT topic that it's subscribed to. You can also choose to download these tokens manually to your source device.

After you've created the tunnel, you can use the browser-based SSH to interact with the remote device directly from the console using the in-context command-line interface. To use this command- line interface, choose the tunnel for the thing that you created, and in the details page, expand the **Command-line interface** section. As the local proxy has already been configured for you, you can start entering commands to quickly get started with accessing and interacting with your remote device, `RemoteDevice1`.

For more information about the quick setup method and using the browser-based SSH, see [Open a tunnel and use browser-based SSH to access remote device](tunneling-tutorial-quick-setup.md).

## Cleaning up
<a name="tunnel-cleanup-existing"></a>
+ 

**Close tunnel**  
We recommend that you close the tunnel after you've finished using it. A tunnel can also become closed if it stayed open for longer than the specified tunnel duration. A tunnel cannot be reopened once closed. You can still duplicate a tunnel by opening the closed tunnel and then choosing **Duplicate tunnel**. Specify the tunnel duration that you want to use and then create the new tunnel.
  + To close an individual tunnel or multiple tunnels from the AWS IoT console, go to the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels), choose the tunnels that you want to close, and then choose **Close tunnel**.
  + To close an individual tunnel or multiple tunnels using the AWS IoT API Reference API, use the [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html) API operation.

    ```
    aws iotsecuretunneling close-tunnel \ 
        --tunnel-id "01234567-89ab-0123-4c56-789a01234bcd"
    ```
+ 

**Delete tunnel**  
You can delete a tunnel permanently from your AWS account.
**Warning**  
Deletion actions are permanent and can't be undone.
  + To delete an individual tunnel or multiple tunnels from the AWS IoT console, go to the [Tunnels hub](https://console.aws.amazon.com/iot/home#/tunnels), choose the tunnels that you want to delete, and then choose **Delete tunnel**.
  + To delete an individual tunnel or multiple tunnels using the AWS IoT API Reference API, use the [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html) API operation. When using the API, set the `delete` flag to `true`.

    ```
    aws iotsecuretunneling close-tunnel \ 
        --tunnel-id "01234567-89ab-0123-4c56-789a01234bcd"
        --delete true
    ```

# Local proxy
<a name="local-proxy"></a>

The local proxy transmits data sent by the application running on the source device by using secure tunneling over a WebSocket secure connection. You can download the local proxy source from [GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy). 

The local proxy can run in two modes: `source` or `destination`. In source mode, the local proxy runs on the same device or network as the client application that initiates the TCP connection. In destination mode, the local proxy runs on the remote device, along with the destination application. A single tunnel can support up to three data streams at a time by using tunnel multiplexing. For each data stream, secure tunneling uses multiple TCP connections, which reduces the potential for a time out. For more information, see [Multiplex data streams and using simultaneous TCP connections in a secure tunnel](multiplexing.md).

# How to use the local proxy
<a name="how-use-local-proxy"></a>

You can run the local proxy on the source and destination devices to transmit data to the secure tunneling endpoints. If your devices are in a network that use a web proxy, the web proxy can intercept the connections before forwarding them to the internet. In this case, you'll need to configure your local proxy to use the web proxy. For more information, see [Configure local proxy for devices that use web proxy](configure-local-proxy-web-proxy.md). 

## Local proxy workflow
<a name="local-proxy-workflow"></a>

The following steps show how the local proxy is run on the source and destination devices.

1. 

**Connect local proxy to secure tunneling**  
First, local proxy must establish a connection to secure tunneling. When you start the local proxy, use the following arguments:
   + The `-r` argument to specify the AWS Region in which the tunnel is opened.
   + The `-t` argument to pass either the source or destination client access token returned from the `OpenTunnel`.
**Note**  
Two local proxies using the same client access token value cannot be connected at the same time.

1. 

**Perform source or destination actions**  
After the WebSocket connection is established, the local proxy performs either source mode or destination mode actions, depending on its configuration.

   By default, the local proxy attempts to reconnect to secure tunneling if any input/output (I/O) errors occur or if the WebSocket connection is closed unexpectedly. This causes the TCP connection to close. If any TCP socket errors occur, the local proxy sends a message through the tunnel to notify the other side to close its TCP connection. By default, the local proxy always uses SSL communication.

1. 

**Stop the local proxy**  
After you use the tunnel, it is safe to stop the local proxy process. We recommend that you explicitly close the tunnel by calling `CloseTunnel`. Active tunnel clients might not be closed right after calling `CloseTunnel`.

For more information about how to use the AWS Management Console to open a tunnel and start an SSH session, see [Open a tunnel and start SSH session to remote device](secure-tunneling-tutorial-open-tunnel.md).

## Local proxy best practices
<a name="local-proxy-security"></a>

When running the local proxy, follow these best practices:
+ Avoid the use of the `-t` local proxy argument to pass in an access token. We recommend that you use the `AWSIOT_TUNNEL_ACCESS_TOKEN` environment variable to set the access token for the local proxy.
+ Run the local proxy executable with least privileges in the operating system or environment.
  + Avoid running the local proxy as an administrator on Windows.
  + Avoid running the local proxy as root on Linux and macOS.
+ Consider running the local proxy on separate hosts, containers, sandboxes, chroot jail, or a virtualized environment.
+ Build the local proxy with relevant security flags, depending on your toolchain.
+ On devices with multiple network interfaces, use the `-b` argument to bind the TCP socket to the network interface used to communicate with the destination application. 

## Example command and output
<a name="example-cmd-output-localproxy"></a>

The following shows an example of a command that you run and the corresponding output. The example shows how the local proxy can be configured in both `source` and `destination` modes. The local proxy upgrades the HTTPS protocol to WebSockets to establish a long-lived connection and then starts transmitting data through the connection to the secure tunneling device endpoints.

**Before you run these commands:**  
You must have opened a tunnel and obtained the client access tokens for the source and destination. You must have also built the local proxy as described previously. To build the local proxy, open the [ local proxy source code](https://github.com/aws-samples/aws-iot-securetunneling-localproxy) in the GitHub repository and follow the instructions for building and installing the local proxy.

**Note**  
The following commands used in the examples use the `verbosity` flag to illustrate an overview of the different steps described previously after you run the local proxy. We recommend that you use this flag only for testing purposes.

**Running local proxy in source mode**  
The following commands display how to run the local proxy in source mode.

------
#### [ Linux/macOS ]

In Linux or macOS, run the following commands in the terminal to configure and start the local proxy on your source.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
./localproxy -s 5555 -v 5 -r us-west-2
```

Where:
+ `-s` is the source listen port, which starts the local proxy in source mode.
+ `-v` is the verbosity of the output, which can be a value between zero and six.
+ `-r` is the endpoint region where the tunnel is opened.

For more information about the parameters, see [Options set using command line arguments](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#options-set-via-command-line-arguments).

------
#### [ Windows ]

In Windows, you configure the local proxy similar to how you do for Linux or macOS, but how you define the environment variables is different from the other platforms. Run the following commands in the `cmd` window to configure and start the local proxy on your source.

```
set AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
.\localproxy -s 5555 -v 5 -r us-west-2
```

Where:
+ `-s` is the source listen port, which starts the local proxy in source mode.
+ `-v` is the verbosity of the output, which can be a value between zero and six.
+ `-r` is the endpoint region where the tunnel is opened.

For more information about the parameters, see [Options set using command line arguments](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#options-set-via-command-line-arguments).

------

**Note**  
When using the latest version of local proxy in source mode, you must include the AWS CLI parameter `--destination-client-type V1` on the source device for backward compatibility. This applies when connecting to any of these destination modes:  
AWS IoT Device Client
AWS IoT Secure Tunneling Component or AWS IoT Greengrass Version 2 Secure Tunneling Component
Any AWS IoT Secure Tunneling demo code written before 2022
1.X versions of the local proxy
This parameter ensures proper communication between the updated source proxy and older destination clients. For more information about local proxy versions, see [AWS IoT Secure Tunneling](https://github.com/aws-samples/aws-iot-securetunneling-localproxy/blob/main/README.md#as-of-312-may-2024-update---destination-client-type-v1-will-be-a-required-parameter-when-connecting-with-the-following) on *GitHub*.

The following is a sample output of running the local proxy in `source` mode.

```
...
...

Starting proxy in source mode
Attempting to establish web socket connection with endpoint wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Resolved proxy  server IP: 10.10.0.11
Connected successfully with proxy server
Performing SSL handshake with proxy server	
Successfully completed SSL handshake with proxy server
HTTP/1.1 101 Switching Protocols

...

Connection: upgrade
channel-id: 01234567890abc23-00001234-0005678a-b1234c5de677a001-2bc3d456
upgrade: websocket

...

Web socket session ID: 01234567890abc23-00001234-0005678a-b1234c5de677a001-2bc3d456
Web socket subprotocol selected: aws.iot.securetunneling-2.0
Successfully established websocket connection with proxy server: wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Setting up web socket pings for every 5000 milliseconds
Scheduled next read:

...

Starting web socket read loop continue reading...
Resolved bind IP: 127.0.0.1
Listening for new connection on port 5555
```

**Running local proxy in destination mode**  
The following commands display how to run the local proxy in destination mode.

------
#### [ Linux/macOS ]

In Linux or macOS, run the following commands in the terminal to configure and start the local proxy on your destination.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
./localproxy -d 22 -v 5 -r us-west-2
```

Where:
+ `-d` is the destination application which starts the local proxy in destination mode.
+ `-v` is the verbosity of the output, which can be a value between zero and six.
+ `-r` is the endpoint region where the tunnel is opened.

For more information about the parameters, see [Options set using command line arguments](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#options-set-via-command-line-arguments).

------
#### [ Windows ]

In Windows, you configure the local proxy similar to how you do for Linux or macOS, but how you define the environment variables is different from the other platforms. Run the following commands in the `cmd` window to configure and start the local proxy on your destination.

```
set AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
.\localproxy -d 22 -v 5 -r us-west-2
```

Where:
+ `-d` is the destination application which starts the local proxy in destination mode.
+ `-v` is the verbosity of the output, which can be a value between zero and six.
+ `-r` is the endpoint region where the tunnel is opened.

For more information about the parameters, see [Options set using command line arguments](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#options-set-via-command-line-arguments).

------

**Note**  
When using the latest version of local proxy in destination mode, you must include the AWS CLI parameter `--destination-client-type V1` on the destination device for backward compatibility. This applies when connecting to either of these source modes:  
Browser-based Secure Tunneling from the AWS Console.
1.X versions of the local proxy
This parameter ensures proper communication between the updated destination proxy and older source clients. For more information about local proxy versions, see [AWS IoT Secure Tunneling](https://github.com/aws-samples/aws-iot-securetunneling-localproxy/blob/main/README.md#as-of-312-may-2024-update---destination-client-type-v1-will-be-a-required-parameter-when-connecting-with-the-following) on *GitHub*.

The following is a sample output of running the local proxy in `destination` mode.

```
...
...

Starting proxy in destination mode
Attempting to establish web socket connection with endpoint wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Resolved proxy  server IP: 10.10.0.11
Connected successfully with proxy server
Performing SSL handshake with proxy server	
Successfully completed SSL handshake with proxy server
HTTP/1.1 101 Switching Protocols

...

Connection: upgrade
channel-id: 01234567890abc23-00001234-0005678a-b1234c5de677a001-2bc3d456
upgrade: websocket

...

Web socket session ID: 01234567890abc23-00001234-0005678a-b1234c5de677a001-2bc3d456
Web socket subprotocol selected: aws.iot.securetunneling-2.0
Successfully established websocket connection with proxy server: wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Setting up web socket pings for every 5000 milliseconds
Scheduled next read:

...

Starting web socket read loop continue reading...
```

# Configure local proxy for devices that use web proxy
<a name="configure-local-proxy-web-proxy"></a>

You can use local proxy on AWS IoT devices to communicate with AWS IoT secure tunneling APIs. The local proxy transmits data sent by the device application using secure tunneling over a WebSocket secure connection. The local proxy can work in `source` or `destination` mode. In `source` mode, it runs on the same device or network that initiates the TCP connection. In `destination` mode, the local proxy runs on the remote device, along with the destination application. For more information, see [Local proxy](local-proxy.md).

The local proxy needs to connect directly to the internet to use AWS IoT secure tunneling. For a long-lived TCP connection with secure tunneling, the local proxy upgrades the HTTPS request to establish a WebSockets connection to one of the [secure tunneling device connection endpoints](https://docs.aws.amazon.com/general/latest/gr/iot_device_management.html).

If your devices are in a network that uses a web proxy, the web proxy can intercept the connections before forwarding them to the internet. To establish a long-lived connection to the secure tunneling device connection endpoints, configure your local proxy to use the web proxy as described in the [websocket specification](https://tools.ietf.org/html/rfc6455#section-4.1).

**Note**  
The [AWS IoT Device Client](iot-sdks.md#iot-sdk-device-client) doesn't support devices that use a web proxy. To work with the web proxy, you'll need to use a local proxy and configure it to work with a web proxy as described below.

The following steps show how the local proxy works with a web proxy.

1. The local proxy sends an HTTP `CONNECT` request to the web proxy that contains the remote address of the secure tunneling service, along with the web proxy authentication information.

1. The web proxy will then create a long-lived connection to the remote secure tunneling endpoints.

1. The TCP connection is established and the local proxy will now work in both source and destination modes for data transmission.

**Topics**
+ [

## Build the local proxy
](#build-local-proxy)
+ [

## Configure your web proxy
](#configure-web-proxy)
+ [

## Configure and start the local proxy
](#configure-start-local-proxy)

## Build the local proxy
<a name="build-local-proxy"></a>

Open the [local proxy source code](https://github.com/aws-samples/aws-iot-securetunneling-localproxy) in the GitHub repository and follow the instructions for building and installing the local proxy.

## Configure your web proxy
<a name="configure-web-proxy"></a>

The local proxy relies on the HTTP tunneling mechanism described by the [HTTP/1.1 specification](https://tools.ietf.org/html/rfc7231#section-4.3.6). To comply with the specifications, your web proxy must allow devices to use the `CONNECT` method.

How you configure your web proxy depends on the web proxy you're using and the web proxy version. To make sure you configure the web proxy correctly, check your web proxy's documentation.

To configure your web proxy, first identify your web proxy URL and confirm whether your web proxy supports HTTP tunneling. The web proxy URL will be used later when you configure and start the local proxy.

1. 

**Identify your web proxy URL**  
Your web proxy URL will be in the following format.

   ```
   protocol://web_proxy_host_domain:web_proxy_port
   ```

   AWS IoT secure tunneling supports only basic authentication for web proxy. To use basic authentication, you must specify the **username** and **password** as part of the web proxy URL. The web proxy URL will be in the following format.

   ```
   protocol://username:password@web_proxy_host_domain:web_proxy_port
   ```
   + *protocol* can be `http` or `https`. We recommend that you use `https`.
   + *web\$1proxy\$1host\$1domain* is the IP address of your web proxy or a DNS name that resolves to the IP address of your web proxy.
   + *web\$1proxy\$1port* is the port on which the web proxy is listening.
   + The web proxy uses this **username** and **password** to authenticate the request.

1. 

**Test your web proxy URL**  
To confirm whether your web proxy supports TCP tunneling, use a `curl` command and make sure that you get a `2xx` or a `3xx` response.

   For example, if your web proxy URL is `https://server.com:1235`, use a `proxy-insecure` flag with the `curl` command because the web proxy might rely on a self-signed certificate.

   ```
   export HTTPS_PROXY=https://server.com:1235
   curl -I https://aws.amazon.com --proxy-insecure
   ```

   If your web proxy URL has a `http` port (for example, `http://server.com:1234`), you don't have to use the `proxy-insecure` flag.

   ```
   export HTTPS_PROXY=http://server.com:1234
   curl -I https://aws.amazon.com
   ```

## Configure and start the local proxy
<a name="configure-start-local-proxy"></a>

To configure the local proxy to use a web proxy, you must configure the `HTTPS_PROXY` environment variable with either the DNS domain names or the IP addresses and port numbers that your web proxy uses.

After you've configured the local proxy, you can use the local proxy as explained in this [README](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#readme) document.

**Note**  
Your environment variable declaration is case sensitive. We recommend that you define each variable once using either all uppercase or all lowercase letters. The following examples show the environment variable declared in uppercase letters. If the same variable is specified using both uppercase and lowercase letters, the variable specified using lowercase letters takes precedence. 

The following commands show how to configure the local proxy that is running on your destination to use the web proxy and start the local proxy.
+ `AWSIOT_TUNNEL_ACCESS_TOKEN`: This variable holds the client access token (CAT) for the destination.
+ `HTTPS_PROXY`: This variable holds the web proxy URL or the IP address for configuring the local proxy.

The commands shown in the following examples depend on the operating system that you use and whether the web proxy is listening on an HTTP or an HTTPS port.

### Web proxy listening on an HTTP port
<a name="configure-start-local-proxy-http"></a>

If your web proxy is listening on an HTTP port, you can provide the web proxy URL or IP address for the `HTTPS_PROXY` variable.

------
#### [ Linux/macOS ]

In Linux or macOS, run the following commands in the terminal to configure and start the local proxy on your destination to use a web proxy listening to an HTTP port.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
export HTTPS_PROXY=http:proxy.example.com:1234
./localproxy -r us-east-1 -d 22
```

If you have to authenticate with the proxy, you must specify a **username** and **password** as part of the `HTTPS_PROXY` variable.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
export HTTPS_PROXY=http://username:password@proxy.example.com:1234
./localproxy -r us-east-1 -d 22
```

------
#### [ Windows ]

In Windows, you configure the local proxy similar to how you do for Linux or macOS, but how you define the environment variables is different from the other platforms. Run the following commands in the `cmd` window to configure and start the local proxy on your destination to use a web proxy listening to an HTTP port.

```
set AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
set HTTPS_PROXY=http://proxy.example.com:1234
.\localproxy -r us-east-1 -d 22
```

If you have to authenticate with the proxy, you must specify a **username** and **password** as part of the `HTTPS_PROXY` variable.

```
set AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
set HTTPS_PROXY=http://username:password@10.15.20.25:1234
.\localproxy -r us-east-1 -d 22
```

------

### Web proxy listening on an HTTPS port
<a name="configure-start-local-proxy-https"></a>

Run the following commands if your web proxy is listening on an HTTPS port. 

**Note**  
If you're using a self-signed certificate for the web proxy or if you're running the local proxy on an OS that doesn't have native OpenSSL support and default configurations, you'll have to set up your web proxy certificates as described in the [Certificate setup](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#certificate-setup) section in the GitHub repository. 

The following commands will look similar to how you configured your web proxy for an HTTP proxy, with the exception that you'll also specify the path to the certificate files that you installed as described previously.

------
#### [ Linux/macOS ]

In Linux or macOS, run the following commands in the terminal to configure the local proxy running on your destination to use a web proxy listening to an HTTPS port.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
export HTTPS_PROXY=http:proxy.example.com:1234
./localproxy -r us-east-1 -d 22 -c /path/to/certs
```

If you have to authenticate with the proxy, you must specify a **username** and **password** as part of the `HTTPS_PROXY` variable.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
export HTTPS_PROXY=http://username:password@proxy.example.com:1234
./localproxy -r us-east-1 -d 22 -c /path/to/certs
```

------
#### [ Windows ]

In Windows, run the following commands in the `cmd` window to configure and start the local proxy running on your destination to use a web proxy listening to an HTTP port.

```
set AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
set HTTPS_PROXY=http://proxy.example.com:1234
.\localproxy -r us-east-1 -d 22 -c \path\to\certs
```

If you have to authenticate with the proxy, you must specify a **username** and **password** as part of the `HTTPS_PROXY` variable.

```
set AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
set HTTPS_PROXY=http://username:password@10.15.20.25:1234
.\localproxy -r us-east-1 -d 22 -c \path\to\certs
```

------

### Example command and output
<a name="example-cmd-output-localproxy-webproxy"></a>

The following shows an example of a command that you run on a Linux OS and the corresponding output. The example shows a web proxy that's listening on an HTTP port and how the local proxy can be configured to use the web proxy in both `source` and `destination` modes. Before you can run these commands, you must have already opened a tunnel and obtained the client access tokens for the source and destination. You must have also built the local proxy and configured your web proxy as described previously.

Here's an overview of the steps after you start the local proxy. The local proxy:
+ Identifies the web proxy URL so that it can use the URL to connect to the proxy server.
+ Establishes a TCP connection with the web proxy.
+ Sends an HTTP `CONNECT` request to the web proxy and waits for the `HTTP/1.1 200` response, which indicates that connection has been established.
+ Upgrades the HTTPS protocol to WebSockets to establish a long-lived connection.
+ Starts transmitting data through the connection to the secure tunneling device endpoints. 

**Note**  
The following commands used in the examples use the `verbosity` flag to illustrate an overview of the different steps described previously after you run the local proxy. We recommend that you use this flag only for testing purposes.

**Running local proxy in source mode**  
The following commands show how to run the local proxy in source mode.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
export HTTPS_PROXY=http:username:password@10.15.10.25:1234
./localproxy -s 5555 -v 5 -r us-west-2
```

The following shows a sample output of running the local proxy in `source` mode.

```
...

Parsed basic auth credentials for the URL
Found Web proxy information in the environment variables, will use it to connect via the proxy.

...

Starting proxy in source mode
Attempting to establish web socket connection with endpoint wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Resolved Web proxy IP: 10.10.0.11
Connected successfully with Web Proxy
Successfully sent HTTP CONNECT to the Web proxy
Full response from the Web proxy:
HTTP/1.1 200 Connection established
TCP tunnel established successfully
Connected successfully with proxy server
Successfully completed SSL handshake with proxy server
Web socket session ID: 0a109afffee745f5-00001341-000b8138-cc6c878d80e8adb0-f186064b
Web socket subprotocol selected: aws.iot.securetunneling-2.0
Successfully established websocket connection with proxy server: wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Seting up web socket pings for every 5000 milliseconds
Scheduled next read:

...

Starting web socket read loop continue reading...
Resolved bind IP: 127.0.0.1
Listening for new connection on port 5555
```

**Running local proxy in destination mode**  
The following commands show how to run the local proxy in destination mode.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=${access_token}
export HTTPS_PROXY=http:username:password@10.15.10.25:1234
./localproxy -d 22 -v 5 -r us-west-2
```

The following shows a sample output of running the local proxy in `destination` mode.

```
...

Parsed basic auth credentials for the URL
Found Web proxy information in the environment variables, will use it to connect via the proxy.

...

Starting proxy in destination mode
Attempting to establish web socket connection with endpoint wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Resolved Web proxy IP: 10.10.0.1
Connected successfully with Web Proxy
Successfully sent HTTP CONNECT to the Web proxy
Full response from the Web proxy:
HTTP/1.1 200 Connection established
TCP tunnel established successfully
Connected successfully with proxy server
Successfully completed SSL handshake with proxy server
Web socket session ID: 06717bfffed3fd05-00001355-000b8315-da3109a85da804dd-24c3d10d
Web socket subprotocol selected: aws.iot.securetunneling-2.0
Successfully established websocket connection with proxy server: wss://data.tunneling.iot.us-west-2.amazonaws.com:443
Seting up web socket pings for every 5000 milliseconds
Scheduled next read:

...

Starting web socket read loop continue reading...
```

# Multiplex data streams and using simultaneous TCP connections in a secure tunnel
<a name="multiplexing"></a>

You can use multiple data streams per tunnel by using the secure tunneling multiplexing feature. With multiplexing, you can troubleshoot devices using multiple data streams. You can also reduce your operational load by eliminating the need to build, deploy, and start multiple local proxies or open multiple tunnels to the same device. For example, multiplexing can be used in case of a web browser that requires sending multiple HTTP and SSH data streams.

For each data stream, AWS IoT secure tunneling supports simultaneous TCP connections. Using simultaneous connections reduces the potential for a time-out in case of multiple requests from the client. For example, it can reduce the loading time when remotely accessing a web server that's local to the destination device.

The following sections explain more about multiplexing and using simultaneous TCP connections, and their different use cases.

**Topics**
+ [

# Multiplexing multiple data streams in a secure tunnel
](multiplexing-multiple-streams.md)
+ [

# Using simultaneous TCP connections in a secure tunnel
](multiplexing-simultaneous-tcp.md)

# Multiplexing multiple data streams in a secure tunnel
<a name="multiplexing-multiple-streams"></a>

You can use the multiplexing feature for devices that use multiple connections or ports. Multiplexing can also be used when you require multiple connections to a remote device to troubleshoot any issues. For example, it can be used in case of a web browser that requires sending multiple HTTP and SSH data streams. The application data from both streams are sent to the device concurrently over the multiplexed tunnel.

## Example use case
<a name="multiplexing-use-case"></a>

Say you need to connect to an on-device web application to change some networking parameters, while simultaneously issuing shell commands through the terminal to verify that the device is working properly with the new networking parameters. In this scenario, you may need to connect to the device through both HTTP and SSH and transfer two parallel data streams to concurrently access the web application and terminal. With the multiplexing feature, these two independent streams can be transferred over the same tunnel at the same time.

![\[A diagram showing IoT cloud architecture with source devices, proxy servers, and destination devices for streaming data over different protocols.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tunnel-multiplexing.png)


## How to set up a multiplexed tunnel
<a name="multiplexing-tutorial"></a>

The following procedure walks you through how to set up a multiplexed tunnel for troubleshooting devices using applications that require connections to multiple ports. You will set up one tunnel with two multiplexed streams: one HTTP stream and one SSH stream.

1. 

**(Optional) Create configuration files**

   You can optionally configure the source and destination device with configuration files. Use configuration files if your port mappings are likely to change frequently. You can skip this step if you prefer to specify the port mapping explicitly using the CLI, or if you don't need to start the local proxy on designated listening ports. For more information about how to use configuration files, see [ Options set via --config](https://github.com/aws-samples/aws-iot-securetunneling-localproxy#options-set-via---config) in GitHub.

   1. On your source device, in the folder where your local proxy will run, create a configuration folder called `Config`. Inside this folder, create a file called `SSHSource.ini` with the following content:

      ```
      HTTP1 = 5555
      SSH1 = 3333
      ```

   1. On your destination device, in the folder where your local proxy will run, create a configuration folder called `Config`. Inside this folder, create a file called `SSHDestination.ini` with the following content:

      ```
      HTTP1 = 80
      SSH1 = 22
      ```

1. 

**Open a tunnel**

   Open a tunnel using the `OpenTunnel` API operation or the `open-tunnel` CLI command. Configure the destination by specifying `SSH1` and `HTTP1` as the services and the name of the AWS IoT thing that corresponds to your remote device. Your SSH and HTTP applications are running on this remote device. You must have already created the IoT thing in the AWS IoT registry. For more information, see [Managing things with the registry](thing-registry.md).

   ```
   aws iotsecuretunneling open-tunnel \
   	--destination-config thingName=RemoteDevice1,services=HTTP1,SSH1
   ```

   Running this command generates the source and destination access tokens which you'll use to run the local proxy.

   ```
   {
   	"tunnelId": "b2de92a3-b8ff-46c0-b0f2-afa28b00cecd",
   	"tunnelArn": "arn:aws:iot:us-west-2:431600097591:tunnel/b2de92a3-b8ff-46c0-b0f2-afa28b00cecd",
   	"sourceAccessToken": source_client_access_token,
   	"destinationAccessToken": destination_client_access_token
   }
   ```

1. 

**Configure and start the local proxy**

   Before you can run the local proxy, either set up the AWS IoT Device Client, or download the local proxy source code from [GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy) and build it for the platform of your choice. You can then start the destination and the source local proxy to connect to the secure tunnel. For more information about configuring and using the local proxy, see [How to use the local proxy](how-use-local-proxy.md).
**Note**  
On your source device, if you don't use any configuration files or specify the port mapping using the CLI, you can still use the same command to run the local proxy. The local proxy in source mode will automatically pick up available ports to use and the mappings for you.

------
#### [ Start local proxy using configuration files ]

   Run the following commands to run the local proxy in the source and destination modes using configuration files.

   ```
   // ----------------- Start the destination local proxy -----------------------
   ./localproxy -r us-east-1 -m dst -t destination_client_access_token
   
   // ----------------- Start the source local proxy ----------------------------
   // You also run the same command below if you want the local proxy to
   // choose the mappings for you instead of using configuration files.
   ./localproxy -r us-east-1 -m src -t source_client_access_token
   ```

------
#### [ Start local proxy using CLI port mapping ]

   Run the following commands to run the local proxy in the source and destination modes by specifying the port mappings explicitly using the CLI.

   ```
   // ----------------- Start the destination local proxy -----------------------------------
   ./localproxy -r us-east-1 -d HTTP1=80,SSH1=22 -t destination_client_access_token
   
   // ----------------- Start the source local proxy ----------------------------------------
   ./localproxy -r us-east-1 -s HTTP1=5555,SSH1=33 -t source_client_access_token
   ```

------

The application data from SSH and HTTP connection can now be transferred concurrently over the multiplexed tunnel. As seen in the map below, the service identifier acts as a readable format to translate the port mapping between the source and destination device. With this configuration, secure tunneling forwards any incoming HTTP traffic from port *5555* on the source device to port *80* on the destination device, and any incoming SSH traffic from port *3333* to port *22* on the destination device.

![\[A translation process for mapping service identifiers from source and destination local proxies to translated port mappings after processing.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/multiplexing-post-mapping-translation.png)


# Using simultaneous TCP connections in a secure tunnel
<a name="multiplexing-simultaneous-tcp"></a>

AWS IoT secure tunneling supports more than one TCP connection simultaneously for each data stream. You can use this capability when you require simultaneous connections to a remote device. Using simultaneous TCP connections reduces the potential for a time-out in case of multiple requests from the client. For example, when accessing a web server that has multiple components running on it, simultaneous TCP connections can reduce the time it takes to load the site. 

**Note**  
Simultaneous TCP connections have a bandwidth limit of 800 Kilobytes per second for each AWS account. AWS IoT secure tunneling can configure this limit for you depending on the number of incoming requests.

## Example use case
<a name="tcp-use-case"></a>

Say you need to remotely access a web server that's local to the destination device and has multiple components running on it. With a single TCP connection, while trying to access the web server, sequential loading can increase the amount of time it takes to load the resources on the site. The simultaneous TCP connections can reduce the loading time by meeting the resource requirements of the site, thereby reducing the access time. The following diagram shows how simultaneous TCP connections are supported for the data stream to the web server application running on the remote device.

**Note**  
If you want to access multiple applications running on the remote device using the tunnel, you can use tunnel multiplexing. For more information, see [Multiplexing multiple data streams in a secure tunnel](multiplexing-multiple-streams.md).

![\[An illustration showing IoT cloud setup with source device, local proxy, proxy servers, and destination device with web server application, connected via TCP and WSS protocols.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/tcp-tunneling.png)


## How to use simultaneous TCP connections
<a name="multiple-tcp-tutorial"></a>

The following procedure walks you through how to use simultaneous TCP connections for accessing the web browser on the remote device. When there are multiple requests from the client, AWS IoT secure tunneling automatically sets up simultaneous TCP connections to handle the requests, thereby reducing the loading time.

1. 

**Open a tunnel**

   Open a tunnel using the `OpenTunnel` API operation or the `open-tunnel` CLI command. Configure the destination by specifying `HTTP` as the service and the name of the AWS IoT thing that corresponds to your remote device. Your web server application is running on this remote device. You must have already created the IoT thing in the AWS IoT registry. For more information, see [Managing things with the registry](thing-registry.md).

   ```
   aws iotsecuretunneling open-tunnel \
   	--destination-config thingName=RemoteDevice1,services=HTTP
   ```

   Running this command generates the source and destination access tokens which you'll use to run the local proxy.

   ```
   {
   	"tunnelId": "b2de92a3-b8ff-46c0-b0f2-afa28b00cecd",
   	"tunnelArn": "arn:aws:iot:us-west-2:431600097591:tunnel/b2de92a3-b8ff-46c0-b0f2-afa28b00cecd",
   	"sourceAccessToken": source_client_access_token,
   	"destinationAccessToken": destination_client_access_token
   }
   ```

1. 

**Configure and start the local proxy**

   Before you can run the local proxy, download the local proxy source code from [GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy) and build it for the platform of your choice. You can then start the destination and the source local proxy to connect to the secure tunnel and start using the remote web server application.
**Note**  
For AWS IoT secure tunneling to use simultaneous TCP connections, you must upgrade to the latest version of the local proxy. This feature is not available if you configure the local proxy using the AWS IoT Device Client.

   ```
   // Start the destination local proxy
   ./localproxy -r us-east-1 -d HTTP=80 -t destination_client_access_token
   
   // Start the source local proxy
   ./localproxy -r us-east-1 -s HTTP=5555 -t source_client_access_token
   ```

   For more information about configuring and using the local proxy, see [How to use the local proxy](how-use-local-proxy.md).

You can now use the tunnel to access the web server application. AWS IoT secure tunneling will automatically set up and handle the simultaneous TCP connections when there are multiple requests from the client.

# Configuring a remote device and using IoT agent
<a name="configure-remote-device"></a>

The IoT agent is used to receive the MQTT message that includes the client access token and start a local proxy on the remote device. You must install and run the IoT agent on the remote device if you want secure tunneling to deliver the client access token using MQTT. The IoT agent must subscribe to the following reserved IoT MQTT topic:

**Note**  
If you want to deliver the destination client access token to the remote device through methods other than subscribing to the reserved MQTT topic, you might need a destination client access token (CAT) listener and a local proxy. The CAT listener must work with your chosen client access token delivery mechanism and be able to start a local proxy in destination mode.

## IoT agent snippet
<a name="agent-snippet"></a>

The IoT agent must subscribe to the following reserved IoT MQTT topic so that it can receive the MQTT message and start the local proxy:

`$aws/things/thing-name/tunnels/notify`

Where `thing-name` is the name of AWS IoT thing associated with the remote device.

The following is an example MQTT message payload:

```
{
    "clientAccessToken": "destination-client-access-token",
    "clientMode": "destination",
    "region": "aws-region",
    "services": ["destination-service"]
}
```

After it receives an MQTT message, the IoT agent must start a local proxy on the remote device with the appropriate parameters.

The following Java code demonstrates how to use the [AWS IoT Device SDK](https://github.com/aws/aws-iot-device-sdk-java) and [ProcessBuilder](https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html) from the Java library to build a simple IoT agent to work with secure tunneling.

```
// Find the IoT device endpoint for your AWS account
final String endpoint = iotClient.describeEndpoint(new DescribeEndpointRequest().withEndpointType("iot:Data-ATS")).getEndpointAddress();

// Instantiate the IoT Agent with your AWS credentials
final String thingName = "RemoteDeviceA";
final String tunnelNotificationTopic = String.format("$aws/things/%s/tunnels/notify", thingName);
final AWSIotMqttClient mqttClient = new AWSIotMqttClient(endpoint, thingName,
                 "your_aws_access_key", "your_aws_secret_key");

try {
    mqttClient.connect();
    final TunnelNotificationListener listener = new TunnelNotificationListener(tunnelNotificationTopic);
    mqttClient.subscribe(listener, true);
}
finally {
    mqttClient.disconnect();
}

private static class TunnelNotificationListener extends AWSIotTopic {
    public TunnelNotificationListener(String topic) {
        super(topic);
    }

    @Override
    public void onMessage(AWSIotMessage message) {
        try {
            // Deserialize the MQTT message
            final JSONObject json = new JSONObject(message.getStringPayload());
 
            final String accessToken = json.getString("clientAccessToken");
            final String region = json.getString("region");
            
            final String clientMode = json.getString("clientMode");
            if (!clientMode.equals("destination")) {
                throw new RuntimeException("Client mode " + clientMode + " in the MQTT message is not expected");
            }

            final JSONArray servicesArray = json.getJSONArray("services");
            if (servicesArray.length() > 1) {
                throw new RuntimeException("Services in the MQTT message has more than 1 service");
            }
            final String service = servicesArray.get(0).toString();
            if (!service.equals("SSH")) {
                throw new RuntimeException("Service " + service + " is not supported");
            }

            // Start the destination local proxy in a separate process to connect to the SSH Daemon listening port 22
            final ProcessBuilder pb = new ProcessBuilder("localproxy",
                        "-t", accessToken,
                        "-r", region,
                        "-d", "localhost:22");
            pb.start();
        }
        catch (Exception e) {
            log.error("Failed to start the local proxy", e);
        }
    }
}
```

# Controlling access to tunnels
<a name="tunnel-access"></a>

Secure tunneling provides service-specific actions, resources, and condition context keys for use in IAM permissions policies.

## Tunnel access prerequisites
<a name="tunnel-access-prereq"></a>
+ Learn how to secure AWS resources by using [IAM policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_controlling.html).
+ Learn how to create and evaluate [IAM conditions](      https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_multi-value-conditions.html).
+ Learn how to secure AWS resources using [resource tags](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html).

## Tunnel access policies
<a name="tunnel-access-policies"></a>

You must use the following policies for authorizing permissions to use the secure tunneling API. For more information about AWS IoT security see [Identity and access management for AWS IoT](security-iam.md).

### iot:OpenTunnel
<a name="open-tunnel-action"></a>

The `iot:OpenTunnel` policy action grants a principal permission to call [OpenTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_OpenTunnel.html).

In the `Resource` element of the IAM policy statement:
+ Specify the wildcard tunnel ARN:

  `arn:aws:iot:aws-region:aws-account-id:tunnel/*`
+ Specify a thing ARN to manage the `OpenTunnel` permission for specific IoT things:

  `arn:aws:iot:aws-region:aws-account-id:thing/thing-name`

For example, the following policy statement allows you to open a tunnel to the IoT thing named `TestDevice`.

```
{
    "Effect": "Allow",
    "Action": "iot:OpenTunnel",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*",
        "arn:aws:iot:aws-region:aws-account-id:thing/TestDevice"
    ]
}
```

The `iot:OpenTunnel` policy action supports the following condition keys:
+ `iot:ThingGroupArn`
+ `iot:TunnelDestinationService`
+ `aws:RequestTag`/*tag-key*
+ `aws:SecureTransport`
+ `aws:TagKeys`

The following policy statement allows you to open a tunnel to the thing if the thing belongs to a thing group with a name that starts with `TestGroup` and the configured destination service on the tunnel is SSH.

```
{
    "Effect": "Allow",
    "Action": "iot:OpenTunnel",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*"
    ],
    "Condition": {
        "ForAnyValue:StringLike": {
            "iot:ThingGroupArn": [
                "arn:aws:iot:aws-region:aws-account-id:thinggroup/TestGroup*"
            ]
        },
        "ForAllValues:StringEquals": {
            "iot:TunnelDestinationService": [
                "SSH"
            ]
        }
    }
}
```

You can also use resource tags to control permission to open tunnels. For example, the following policy statement allows a tunnel to be opened if the tag key `Owner` is present with a value of `Admin` and no other tags are specified. For general information about using tags, see [Tagging your AWS IoT resources](tagging-iot.md).

```
{
    "Effect": "Allow",
    "Action": "iot:OpenTunnel",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*"
    ],
    "Condition": {
        "StringEquals": {
            "aws:RequestTag/Owner": "Admin"
        },
        "ForAllValues:StringEquals": {
            "aws:TagKeys": "Owner"
        }
    }
}
```

### iot:RotateTunnelAccessToken
<a name="rotate-tunnel-action"></a>

The `iot:RotateTunnelAccessToken` policy action grants a principal permission to call [RotateTunnelAccessToken](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_RorateTunnelAccessToken.html).

In the `Resource` element of the IAM policy statement:
+ Specify a fully qualified tunnel ARN:

  `arn:aws:iot:aws-region: aws-account-id:tunnel/tunnel-id`

  You can also use the wildcard tunnel ARN:

  `arn:aws:iot:aws-region:aws-account-id:tunnel/*`
+ Specify a thing ARN to manage the `RotateTunnelAccessToken` permission for specific IoT things:

  `arn:aws:iot:aws-region:aws-account-id:thing/thing-name`

For example, the following policy statement allows you to rotate either a tunnel's source access token or a client's destination access token for the IoT thing named `TestDevice`.

```
{
    "Effect": "Allow",
    "Action": "iot:RotateTunnelAccessToken",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*",
        "arn:aws:iot:aws-region:aws-account-id:thing/TestDevice"
    ]
}
```

The `iot:RotateTunnelAccessToken` policy action supports the following condition keys:
+ `iot:ThingGroupArn`
+ `iot:TunnelDestinationService`
+ `iot:ClientMode`
+ `aws:SecureTransport`

The following policy statement allows you to rotate the destination access token to the thing if the thing belongs to a thing group with a name that starts with `TestGroup`, the configured destination service on the tunnel is SSH, and the client is in `DESTINATION` mode.

```
{
    "Effect": "Allow",
    "Action": "iot:RotateTunnelAccessToken",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*"
    ],
    "Condition": {
        "ForAnyValue:StringLike": {
            "iot:ThingGroupArn": [
                "arn:aws:iot:aws-region:aws-account-id:thinggroup/TestGroup*"
            ]
        },
        "ForAllValues:StringEquals": {
            "iot:TunnelDestinationService": [
                "SSH"
            ],
            "iot:ClientMode": "DESTINATION"
        }
    }
}
```

### iot:DescribeTunnel
<a name="describe-tunnel-action"></a>

The `iot:DescribeTunnel` policy action grants a principal permission to call [DescribeTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_DescribeTunnel.html).

In the `Resource` element of the IAM policy statement, specify a fully qualified tunnel ARN:

`arn:aws:iot:aws-region: aws-account-id:tunnel/tunnel-id`

You can also use the wildcard ARN:

`arn:aws:iot:aws-region:aws-account-id:tunnel/*`

The `iot:DescribeTunnel` policy action supports the following condition keys:
+ `aws:ResourceTag/tag-key`
+ `aws:SecureTransport`

The following policy statement allows you to call `DescribeTunnel` if the requested tunnel is tagged with the key `Owner` with a value of `Admin`.

```
{
    "Effect": "Allow",
    "Action": "iot:DescribeTunnel",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*"
    ],
    "Condition": {
        "StringEquals": {
            "aws:ResourceTag/Owner": "Admin"
        }
    }
}
```

### iot:ListTunnels
<a name="list-tunnels-action"></a>

The `iot:ListTunnels` policy action grants a principal permission to call [ListTunnels](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_ListTunnels.html).

In the `Resource` element of the IAM policy statement:
+ Specify the wildcard tunnel ARN:

  `arn:aws:iot:aws-region:aws-account-id:tunnel/*`
+ Specify a thing ARN to manage the `ListTunnels` permission on selected IoT things:

  `arn:aws:iot:aws-region:aws-account-id:thing/thing-name`

The `iot:ListTunnels` policy action supports the condition key `aws:SecureTransport`.

The following policy statement allows you to list tunnels for the thing named `TestDevice`.

```
{
    "Effect": "Allow",
    "Action": "iot:ListTunnels",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*",
        "arn:aws:iot:aws-region:aws-account-id:thing/TestDevice"
    ]
}
```

### iot:ListTagsForResource
<a name="list-tags-for-resource-action"></a>

The `iot:ListTagsForResource` policy action grants a principal permission to call `ListTagsForResource`.

In the `Resource` element of the IAM policy statement, specify a fully qualified tunnel ARN:

`arn:aws:iot:aws-region: aws-account-id:tunnel/tunnel-id`

You can also use the wildcard tunnel ARN:

`arn:aws:iot:aws-region:aws-account-id:tunnel/*`

The `iot:ListTagsForResource` policy action supports the condition key `aws:SecureTransport`.

### iot:CloseTunnel
<a name="close-tunnel-action"></a>

The `iot:CloseTunnel` policy action grants a principal permission to call [CloseTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_CloseTunnel.html).

In the `Resource` element of the IAM policy statement, specify a fully qualified tunnel ARN:

`arn:aws:iot:aws-region: aws-account-id:tunnel/tunnel-id`

You can also use the wildcard tunnel ARN:

`arn:aws:iot:aws-region:aws-account-id:tunnel/*`

The `iot:CloseTunnel` policy action supports the following condition keys:
+ `iot:Delete`
+ `aws:ResourceTag/tag-key`
+ `aws:SecureTransport`

The following policy statement allows you to call `CloseTunnel` if the request's `Delete` parameter is `false` and the requested is tagged with the key `Owner` with a value of `QATeam`.

```
{
    "Effect": "Allow",
    "Action": "iot:CloseTunnel",
    "Resource": [
        "arn:aws:iot:aws-region:aws-account-id:tunnel/*"
    ],
    "Condition": {
        "Bool": {
            "iot:Delete": "false"
        },
        "StringEquals": {
            "aws:ResourceTag/Owner": "QATeam"
        }
    }
}
```

### iot:TagResource
<a name="tag-resource-action"></a>

The `iot:TagResource` policy action grants a principal permission to call `TagResource`.

In the `Resource` element of the IAM policy statement, specify a fully qualified tunnel ARN:

`arn:aws:iot:aws-region: aws-account-id:tunnel/tunnel-id`

You can also use the wildcard tunnel ARN:

`arn:aws:iot:aws-region:aws-account-id:tunnel/*`

The `iot:TagResource` policy action supports the condition key `aws:SecureTransport`.

### iot:UntagResource
<a name="untag-resource-action"></a>

The `iot:UntagResource` policy action grants a principal permission to call `UntagResource`.

In the `Resource` element of the IAM policy statement, specify a fully qualified tunnel ARN:

`arn:aws:iot:aws-region: aws-account-id:tunnel/tunnel-id`

You can also use the wildcard tunnel ARN:

`arn:aws:iot:aws-region:aws-account-id:tunnel/*`

The `iot:UntagResource` policy action supports the condition key `aws:SecureTransport`.

# Resolving AWS IoT secure tunneling connectivity issues by rotating client access tokens
<a name="iot-secure-tunneling-troubleshooting"></a>

When you use AWS IoT secure tunneling, you might run into connectivity issues even if the tunnel is open. The following sections show some possible issues and how you can resolve them by rotating the client access tokens. To rotate the client access token (CAT), use the [RotateTunnelAccessToken](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_RotateTunnelAccessToken.html) API or the [rotate-tunnel-access-token](https://docs.aws.amazon.com/cli/latest/reference/iotsecuretunneling/rotate-tunnel-access-token.html) AWS CLI. Depending on whether you run into an error with using the client in the source or destination mode, you can rotate the CAT either in source or destination mode, or both.

**Note**  
If you're not sure whether the CAT needs to be rotated on the source or destination, you can rotate the CAT on both the source and destination by setting `ClientMode` to ALL when using the `RotateTunnelAccessToken` API.
Rotating the CAT doesn't extend the tunnel duration. For example, say the tunnel duration is 12 hours and the tunnel has already been open for 4 hours. When you rotate the access tokens, the new tokens that are generated can only be used for the remaining 8 hours.

**Topics**
+ [

## Invalid client access token error
](#invalid-access-token)
+ [

## Client token mismatch error
](#client-token-mismatch)
+ [

## Remote device connectivity issues
](#tunnel-open-device-error)

## Invalid client access token error
<a name="invalid-access-token"></a>

When using AWS IoT secure tunneling, you can run into a connection error when using the same client access token (CAT) to reconnect to the same tunnel. In this case, the local proxy can't connect to the secure tunneling proxy server. If you're using a client in the source mode, you might see the following error message:

```
Invalid access token: The access token was previously used and cannot be used again
```

The error occurs because the client access token (CAT) can only be used once by the local proxy, and it then becomes invalid. To resolve this error, rotate the client access token in the `SOURCE` mode to generate a new CAT for the source. For an example that shows how to rotate the source CAT, see [Rotate source CAT example](#rotate-token-source-example).

## Client token mismatch error
<a name="client-token-mismatch"></a>

**Note**  
Using client tokens to reuse the CAT is not recommended. We recommend that you use the `RotateTunnelAccessToken` API instead to rotate the client access tokens to reconnect to the tunnel.

If you're using client tokens, you can reuse the CAT for reconnecting to the tunnel. To reuse the CAT, you must provide the client token with the CAT the first time you connect to secure tunneling. Secure tunneling stores the client token so for subsequent connection attempts using the same token, the client token must also be provided. For more information about using client tokens, see the [ local proxy reference implementation in GitHub](https://github.com/aws-samples/aws-iot-securetunneling-localproxy/blob/master/V2WebSocketProtocolGuide.md).

When using client tokens, if you're using a client in the source mode, you might see the following error:

```
Invalid client token: The provided client token does not match the client token 
				that was previously set.
```

The error occurs because the client token provided doesn't match the client token that was provided with the CAT when accessing the tunnel. To resolve this error, rotate the CAT in the `SOURCE` mode to generate a new CAT for the source. The following shows an example:

### Rotate source CAT example
<a name="rotate-token-source-example"></a>

The following shows an example of how to run the `RotateTunnelAccessToken` API in the `SOURCE` mode to generate a new CAT for the source:

```
aws iotsecuretunneling rotate-tunnel-access-token \ 
    --region <region> \ 
    --tunnel-id <tunnel-id> \ 
    --client-mode SOURCE
```

Running this command generates a new source access token and returns the ARN of your tunnel.

```
{
    "sourceAccessToken": "<source-access-token>", 
    "tunnelArn": "arn:aws:iot:<region>:<account-id>:tunnel/<tunnel-id>"
}
```

You can now use the new source token to connect the local proxy in source mode.

```
export AWSIOT_TUNNEL_ACCESS_TOKEN=<source-access-token>
./localproxy -r <region> -s <port>
```

The following shows a sample output of running the local proxy:

```
...

[info]    Starting proxy in source mode
...
[info]    Successfully established websocket connection with proxy server ...
[info]    Listening for new connection on port <port>
...
```

## Remote device connectivity issues
<a name="tunnel-open-device-error"></a>

When using AWS IoT secure tunneling, the device might get disconnected unexpectedly even if the tunnel is open. To identify whether a device is still connected to the tunnel, you can use the [ DescribeTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_DescribeTunnel.html) API or the [describe-tunnel](https://docs.aws.amazon.com/cli/latest/reference/iotsecuretunneling/describe-tunnel.html) AWS CLI.

A device can get disconnected for multiple reasons. To resolve the connectivity issue, you can rotate the CAT on the destination if the device was disconnected due to the following possible reasons:
+ The CAT on the destination became invalid.
+ The token wasn't delivered to the device over the secure tunneling reserved MQTT topic:

  `$aws/things/<thing-name>/tunnels/notify`

The following example shows how to resolve this issue:

### Rotate destination CAT example
<a name="rotate-token-dest-example"></a>

Consider a remote device, `<RemoteThing1>`. To open a tunnel for that thing, you can use the following command:

```
aws iotsecuretunneling open-tunnel \ 
    --region <region> \ 
    --destination-config thingName=<RemoteThing1>,services=SSH
```

Running this command generates the tunnel details and the CAT for your source and destination.

```
{
    "sourceAccessToken": "<source-access-token>", 
    "destinationAccessToken": "<destination-access-token>", 
    "tunnelId": "<tunnel-id>", 
    "tunnelArn": "arn:aws:iot:<region>:<account-id>:tunnel/tunnel-id"
}
```

However, when you use the [DescribeTunnel](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_DescribeTunnel.html) API, the output indicates that the device has been disconnected, as illustrated below:

```
aws iotsecuretunneling describe-tunnel \ 
    --tunnel-id <tunnel-id> \ 
    --region <region>
```

Running this command displays that the device is still not connected.

```
{
    "tunnel": {
        ...
        "destinationConnectionState": {
            "status": "DISCONNECTED"
        },
        ...
    }
}
```

To resolve this error, run the `RotateTunnelAccessToken` API with the client in `DESTINATION` mode and the configurations for the destination. Running this command revokes the old access token, generates a new token, and resends this token to the MQTT topic:

`$aws/things/<thing-name>/tunnels/notify`

```
aws iotsecuretunneling rotate-tunnel-access-token \ 
    --tunnel-id <tunnel-id> \ 
    --client-mode DESTINATION \ 
    --destination-config thingName=<RemoteThing1>,services=SSH \ 
    --region <region>
```

Running this command generates the new access token as shown below. The token is then delivered to the device to connect to the tunnel, if the device agent is set up correctly.

```
{
    "destinationAccessToken": "destination-access-token", 
    "tunnelArn": "arn:aws:iot:region:account-id:tunnel/tunnel-id"
}
```