The aws:transfer/server:Server resource, part of the Pulumi AWS provider, provisions AWS Transfer Family servers that provide managed SFTP, FTPS, FTP, and AS2 endpoints for file transfers. This guide focuses on three capabilities: endpoint types (public vs VPC), identity provider options (AWS-managed, Active Directory, Lambda, API Gateway), and security policies and structured logging.
Transfer servers may reference VPC infrastructure, AWS Directory Service directories, Lambda functions, or IAM roles depending on configuration. The examples are intentionally small. Combine them with your own networking, authentication infrastructure, and user management.
Create a public SFTP server with tags
Most deployments begin with a basic server that uses AWS-managed authentication and exposes an SFTP endpoint over the public internet.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.transfer.Server("example", {tags: {
Name: "Example",
}});
import pulumi
import pulumi_aws as aws
example = aws.transfer.Server("example", tags={
"Name": "Example",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/transfer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := transfer.NewServer(ctx, "example", &transfer.ServerArgs{
Tags: pulumi.StringMap{
"Name": pulumi.String("Example"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Transfer.Server("example", new()
{
Tags =
{
{ "Name", "Example" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.transfer.Server;
import com.pulumi.aws.transfer.ServerArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Server("example", ServerArgs.builder()
.tags(Map.of("Name", "Example"))
.build());
}
}
resources:
example:
type: aws:transfer:Server
properties:
tags:
Name: Example
Without explicit configuration, the server defaults to a PUBLIC endpoint accessible over the internet, uses SERVICE_MANAGED identity provider for AWS-managed users, and supports only the SFTP protocol. The tags property adds metadata for organization and cost tracking.
Apply a specific security policy
Organizations with compliance requirements enforce specific cryptographic algorithms and TLS versions through security policies.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.transfer.Server("example", {securityPolicyName: "TransferSecurityPolicy-2020-06"});
import pulumi
import pulumi_aws as aws
example = aws.transfer.Server("example", security_policy_name="TransferSecurityPolicy-2020-06")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/transfer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := transfer.NewServer(ctx, "example", &transfer.ServerArgs{
SecurityPolicyName: pulumi.String("TransferSecurityPolicy-2020-06"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Transfer.Server("example", new()
{
SecurityPolicyName = "TransferSecurityPolicy-2020-06",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.transfer.Server;
import com.pulumi.aws.transfer.ServerArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Server("example", ServerArgs.builder()
.securityPolicyName("TransferSecurityPolicy-2020-06")
.build());
}
}
resources:
example:
type: aws:transfer:Server
properties:
securityPolicyName: TransferSecurityPolicy-2020-06
The securityPolicyName property controls which ciphers, key exchange algorithms, and TLS versions the server accepts. AWS provides multiple policies ranging from permissive (2018-11) to restrictive (FIPS variants), allowing you to balance compatibility with security requirements.
Deploy into a VPC with Elastic IPs
To restrict access to specific IP addresses or integrate with on-premises networks, deploy servers into VPCs with static Elastic IPs.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.transfer.Server("example", {
endpointType: "VPC",
endpointDetails: {
addressAllocationIds: [exampleAwsEip.id],
subnetIds: [exampleAwsSubnet.id],
vpcId: exampleAwsVpc.id,
},
});
import pulumi
import pulumi_aws as aws
example = aws.transfer.Server("example",
endpoint_type="VPC",
endpoint_details={
"address_allocation_ids": [example_aws_eip["id"]],
"subnet_ids": [example_aws_subnet["id"]],
"vpc_id": example_aws_vpc["id"],
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/transfer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := transfer.NewServer(ctx, "example", &transfer.ServerArgs{
EndpointType: pulumi.String("VPC"),
EndpointDetails: &transfer.ServerEndpointDetailsArgs{
AddressAllocationIds: pulumi.StringArray{
exampleAwsEip.Id,
},
SubnetIds: pulumi.StringArray{
exampleAwsSubnet.Id,
},
VpcId: pulumi.Any(exampleAwsVpc.Id),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Transfer.Server("example", new()
{
EndpointType = "VPC",
EndpointDetails = new Aws.Transfer.Inputs.ServerEndpointDetailsArgs
{
AddressAllocationIds = new[]
{
exampleAwsEip.Id,
},
SubnetIds = new[]
{
exampleAwsSubnet.Id,
},
VpcId = exampleAwsVpc.Id,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.transfer.Server;
import com.pulumi.aws.transfer.ServerArgs;
import com.pulumi.aws.transfer.inputs.ServerEndpointDetailsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Server("example", ServerArgs.builder()
.endpointType("VPC")
.endpointDetails(ServerEndpointDetailsArgs.builder()
.addressAllocationIds(exampleAwsEip.id())
.subnetIds(exampleAwsSubnet.id())
.vpcId(exampleAwsVpc.id())
.build())
.build());
}
}
resources:
example:
type: aws:transfer:Server
properties:
endpointType: VPC
endpointDetails:
addressAllocationIds:
- ${exampleAwsEip.id}
subnetIds:
- ${exampleAwsSubnet.id}
vpcId: ${exampleAwsVpc.id}
Setting endpointType to VPC removes public internet access. The endpointDetails block specifies which VPC, subnets, and Elastic IP allocations to use. This configuration provides stable IP addresses for firewall rules and private network connectivity.
Authenticate users with AWS Directory Service
Enterprises with existing Active Directory infrastructure can integrate Transfer servers with AWS Managed Active Directory or AD Connector.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.transfer.Server("example", {
identityProviderType: "AWS_DIRECTORY_SERVICE",
directoryId: exampleAwsDirectoryServiceDirectory.id,
});
import pulumi
import pulumi_aws as aws
example = aws.transfer.Server("example",
identity_provider_type="AWS_DIRECTORY_SERVICE",
directory_id=example_aws_directory_service_directory["id"])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/transfer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := transfer.NewServer(ctx, "example", &transfer.ServerArgs{
IdentityProviderType: pulumi.String("AWS_DIRECTORY_SERVICE"),
DirectoryId: pulumi.Any(exampleAwsDirectoryServiceDirectory.Id),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Transfer.Server("example", new()
{
IdentityProviderType = "AWS_DIRECTORY_SERVICE",
DirectoryId = exampleAwsDirectoryServiceDirectory.Id,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.transfer.Server;
import com.pulumi.aws.transfer.ServerArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Server("example", ServerArgs.builder()
.identityProviderType("AWS_DIRECTORY_SERVICE")
.directoryId(exampleAwsDirectoryServiceDirectory.id())
.build());
}
}
resources:
example:
type: aws:transfer:Server
properties:
identityProviderType: AWS_DIRECTORY_SERVICE
directoryId: ${exampleAwsDirectoryServiceDirectory.id}
Setting identityProviderType to AWS_DIRECTORY_SERVICE and providing a directoryId connects the server to your directory. Users authenticate with their AD credentials, and the directory controls access permissions centrally.
Integrate custom authentication with Lambda
Teams with custom identity providers or complex authentication logic can use Lambda functions to validate credentials dynamically.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.transfer.Server("example", {
identityProviderType: "AWS_LAMBDA",
"function": exampleAwsLambdaIdentityProvider.arn,
});
import pulumi
import pulumi_aws as aws
example = aws.transfer.Server("example",
identity_provider_type="AWS_LAMBDA",
function=example_aws_lambda_identity_provider["arn"])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/transfer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := transfer.NewServer(ctx, "example", &transfer.ServerArgs{
IdentityProviderType: pulumi.String("AWS_LAMBDA"),
Function: pulumi.Any(exampleAwsLambdaIdentityProvider.Arn),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Transfer.Server("example", new()
{
IdentityProviderType = "AWS_LAMBDA",
Function = exampleAwsLambdaIdentityProvider.Arn,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.transfer.Server;
import com.pulumi.aws.transfer.ServerArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Server("example", ServerArgs.builder()
.identityProviderType("AWS_LAMBDA")
.function(exampleAwsLambdaIdentityProvider.arn())
.build());
}
}
resources:
example:
type: aws:transfer:Server
properties:
identityProviderType: AWS_LAMBDA
function: ${exampleAwsLambdaIdentityProvider.arn}
Setting identityProviderType to AWS_LAMBDA and providing a function ARN delegates authentication to your Lambda function. The function receives credentials, validates them against your identity system, and returns user permissions and home directory mappings.
Send structured logs to CloudWatch
Production deployments enable logging to CloudWatch for monitoring file transfer activity and meeting audit requirements.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const transfer = new aws.cloudwatch.LogGroup("transfer", {namePrefix: "transfer_test_"});
const transferAssumeRole = aws.iam.getPolicyDocument({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: ["transfer.amazonaws.com"],
}],
actions: ["sts:AssumeRole"],
}],
});
const iamForTransfer = new aws.iam.Role("iam_for_transfer", {
namePrefix: "iam_for_transfer_",
assumeRolePolicy: transferAssumeRole.then(transferAssumeRole => transferAssumeRole.json),
managedPolicyArns: ["arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess"],
});
const transferServer = new aws.transfer.Server("transfer", {
endpointType: "PUBLIC",
loggingRole: iamForTransfer.arn,
protocols: ["SFTP"],
structuredLogDestinations: [pulumi.interpolate`${transfer.arn}:*`],
});
import pulumi
import pulumi_aws as aws
transfer = aws.cloudwatch.LogGroup("transfer", name_prefix="transfer_test_")
transfer_assume_role = aws.iam.get_policy_document(statements=[{
"effect": "Allow",
"principals": [{
"type": "Service",
"identifiers": ["transfer.amazonaws.com"],
}],
"actions": ["sts:AssumeRole"],
}])
iam_for_transfer = aws.iam.Role("iam_for_transfer",
name_prefix="iam_for_transfer_",
assume_role_policy=transfer_assume_role.json,
managed_policy_arns=["arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess"])
transfer_server = aws.transfer.Server("transfer",
endpoint_type="PUBLIC",
logging_role=iam_for_transfer.arn,
protocols=["SFTP"],
structured_log_destinations=[transfer.arn.apply(lambda arn: f"{arn}:*")])
package main
import (
"fmt"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/transfer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
transfer, err := cloudwatch.NewLogGroup(ctx, "transfer", &cloudwatch.LogGroupArgs{
NamePrefix: pulumi.String("transfer_test_"),
})
if err != nil {
return err
}
transferAssumeRole, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef("Allow"),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "Service",
Identifiers: []string{
"transfer.amazonaws.com",
},
},
},
Actions: []string{
"sts:AssumeRole",
},
},
},
}, nil)
if err != nil {
return err
}
iamForTransfer, err := iam.NewRole(ctx, "iam_for_transfer", &iam.RoleArgs{
NamePrefix: pulumi.String("iam_for_transfer_"),
AssumeRolePolicy: pulumi.String(transferAssumeRole.Json),
ManagedPolicyArns: pulumi.StringArray{
pulumi.String("arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess"),
},
})
if err != nil {
return err
}
_, err = transfer.NewServer(ctx, "transfer", &transfer.ServerArgs{
EndpointType: pulumi.String("PUBLIC"),
LoggingRole: iamForTransfer.Arn,
Protocols: pulumi.StringArray{
pulumi.String("SFTP"),
},
StructuredLogDestinations: pulumi.StringArray{
transfer.Arn.ApplyT(func(arn string) (string, error) {
return fmt.Sprintf("%v:*", arn), nil
}).(pulumi.StringOutput),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var transfer = new Aws.CloudWatch.LogGroup("transfer", new()
{
NamePrefix = "transfer_test_",
});
var transferAssumeRole = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "Service",
Identifiers = new[]
{
"transfer.amazonaws.com",
},
},
},
Actions = new[]
{
"sts:AssumeRole",
},
},
},
});
var iamForTransfer = new Aws.Iam.Role("iam_for_transfer", new()
{
NamePrefix = "iam_for_transfer_",
AssumeRolePolicy = transferAssumeRole.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
ManagedPolicyArns = new[]
{
"arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess",
},
});
var transferServer = new Aws.Transfer.Server("transfer", new()
{
EndpointType = "PUBLIC",
LoggingRole = iamForTransfer.Arn,
Protocols = new[]
{
"SFTP",
},
StructuredLogDestinations = new[]
{
transfer.Arn.Apply(arn => $"{arn}:*"),
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogGroup;
import com.pulumi.aws.cloudwatch.LogGroupArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.transfer.Server;
import com.pulumi.aws.transfer.ServerArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var transfer = new LogGroup("transfer", LogGroupArgs.builder()
.namePrefix("transfer_test_")
.build());
final var transferAssumeRole = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("Service")
.identifiers("transfer.amazonaws.com")
.build())
.actions("sts:AssumeRole")
.build())
.build());
var iamForTransfer = new Role("iamForTransfer", RoleArgs.builder()
.namePrefix("iam_for_transfer_")
.assumeRolePolicy(transferAssumeRole.json())
.managedPolicyArns("arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess")
.build());
var transferServer = new Server("transferServer", ServerArgs.builder()
.endpointType("PUBLIC")
.loggingRole(iamForTransfer.arn())
.protocols("SFTP")
.structuredLogDestinations(transfer.arn().applyValue(_arn -> String.format("%s:*", _arn)))
.build());
}
}
resources:
transfer:
type: aws:cloudwatch:LogGroup
properties:
namePrefix: transfer_test_
iamForTransfer:
type: aws:iam:Role
name: iam_for_transfer
properties:
namePrefix: iam_for_transfer_
assumeRolePolicy: ${transferAssumeRole.json}
managedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess
transferServer:
type: aws:transfer:Server
name: transfer
properties:
endpointType: PUBLIC
loggingRole: ${iamForTransfer.arn}
protocols:
- SFTP
structuredLogDestinations:
- ${transfer.arn}:*
variables:
transferAssumeRole:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- transfer.amazonaws.com
actions:
- sts:AssumeRole
The loggingRole grants Transfer Family permissions to write logs. The structuredLogDestinations property specifies CloudWatch Log Group ARNs that receive detailed transfer events. Structured logs include authentication attempts, file operations, and error conditions in a queryable format.
Beyond these examples
These snippets focus on specific server-level features: endpoint types and network placement, identity provider integration, and security policies and logging. They’re intentionally minimal rather than full file transfer solutions.
The examples may reference pre-existing infrastructure such as VPC subnets, Elastic IPs, and security groups (for VPC endpoints), AWS Directory Service directories (for AD authentication), and Lambda functions (for custom authentication). They focus on configuring the server rather than provisioning everything around it.
To keep things focused, common server patterns are omitted, including:
- Protocol-specific configuration (FTP, FTPS, AS2 via protocols property)
- Host key management for server identity (hostKey)
- Custom domain names and certificates (certificate, domain properties)
- Workflow automation (workflowDetails)
These omissions are intentional: the goal is to illustrate how each server feature is wired, not provide drop-in file transfer modules. See the Transfer Server resource reference for all available configuration options.
Let's create AWS Transfer Family Servers
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Identity & Authentication
Each identity provider type requires specific configuration:
SERVICE_MANAGED(default): No additional configuration neededAPI_GATEWAY: RequiresurlandinvocationRoleAWS_DIRECTORY_SERVICE: RequiresdirectoryIdAWS_LAMBDA: Requiresfunction(Lambda ARN)
API_GATEWAY or AWS_LAMBDA identity providers, you can configure sftpAuthenticationMethods with: PASSWORD, PUBLIC_KEY, PUBLIC_KEY_OR_PASSWORD (default), or PUBLIC_KEY_AND_PASSWORD.identityProviderType is immutable and cannot be changed after creation. You must recreate the server to use a different identity provider.Networking & Endpoints
endpointType is set to VPC, your IAM principal needs ec2:DescribeVpcEndpoints and ec2:ModifyVpcEndpoint permissions.endpointType to VPC and configure endpointDetails with subnetIds, vpcId, and optionally addressAllocationIds for Elastic IPs.PUBLIC (default) makes your server accessible over the public internet. VPC or VPC_ENDPOINT restricts access to within your VPC, requiring endpointDetails configuration.Protocols & Security
SFTP. Available protocols are: AS2 (Applicability Statement 2), SFTP (SSH), FTPS (TLS encryption), and FTP (unencrypted).protocols includes FTPS, you must provide an ACM certificate ARN in the certificate property.TransferSecurityPolicy-2018-11. Available policies include standard policies (2018-11 through 2025-03), FIPS policies, PQ-SSH experimental policies, restricted policies, and SSH audit-compliant policies. See the AWS documentation for details on each policy.Configuration & Lifecycle
domain (S3 or EFS storage) and identityProviderType (authentication mode). Changing either requires recreating the server.forceDestroy to true to automatically delete all associated users before destroying the server. This only applies to servers with SERVICE_MANAGED identity provider (default is false).preAuthenticationLoginBanner instead, which displays before authentication.hostKey argument cannot be read via the API during import. You’ll see a difference on the first run after importing, which is expected behavior.Logging & Monitoring
loggingRole with an IAM role ARN (with CloudWatch write permissions) and set structuredLogDestinations to an array of CloudWatch Log Group ARNs.aws.transfer.Tag resource to manage system tags required for custom hostnames, rather than the tags property on the server resource.Using a different cloud?
Explore integration guides for other cloud providers: