This document describes advanced Docker networking configurations for LocalStack, including container-to-container communication, network alias configuration, debugging, and troubleshooting.
Configure LocalStack to run within a Docker network for container-to-container communication.
/**
* Attaches the container to a Docker network
* Enables communication between LocalStack and other containers on the same network
* Inherited from GenericContainer
*
* @param network The Docker network to attach to
* @return This container object for method chaining
*/
public LocalStackContainer withNetwork(Network network);
/**
* Sets network aliases for the container within the Docker network
* The last alias in the list is used as the external hostname (HOSTNAME_EXTERNAL or LOCALSTACK_HOST)
* Inherited from GenericContainer
*
* @param aliases One or more network alias names
* @return This container object for method chaining
*/
public LocalStackContainer withNetworkAliases(String... aliases);import org.testcontainers.containers.Network;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.containers.localstack.LocalStackContainer.Service;
// Create a Docker network
Network network = Network.newNetwork();
// Attach LocalStack to the network
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3, Service.SQS);
localstack.start();
// Test code running on host uses getEndpoint()
URI endpoint = localstack.getEndpoint();
System.out.println("Host endpoint: " + endpoint);
// Output: http://192.168.1.100:49153
// Containers within the network use the alias
System.out.println("Network endpoint: http://localstack:4566");Network network = Network.newNetwork();
// Set multiple aliases - the last one is used as HOSTNAME_EXTERNAL
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("aws", "localstack-container", "localstack") // "localstack" is used
.withServices(Service.S3);
localstack.start();
// All aliases can be used within the network
// http://aws:4566
// http://localstack-container:4566
// http://localstack:4566
// Verify which alias is used for HOSTNAME_EXTERNAL
String hostnameExternal = localstack.getEnvMap().get("HOSTNAME_EXTERNAL");
String localstackHost = localstack.getEnvMap().get("LOCALSTACK_HOST");
System.out.println("HOSTNAME_EXTERNAL: " + hostnameExternal); // "localstack" (for < 2.0)
System.out.println("LOCALSTACK_HOST: " + localstackHost); // "localstack" (for >= 2.0)import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
Network network = Network.newNetwork();
// Start LocalStack
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3, Service.DYNAMODB);
localstack.start();
// Start application container on the same network
GenericContainer<?> app = new GenericContainer<>("myapp:latest")
.withNetwork(network)
.withEnv("AWS_ENDPOINT", "http://localstack:4566")
.withEnv("AWS_ACCESS_KEY_ID", localstack.getAccessKey())
.withEnv("AWS_SECRET_ACCESS_KEY", localstack.getSecretKey())
.withEnv("AWS_REGION", localstack.getRegion())
.withExposedPorts(8080);
app.start();
// The app container can now access LocalStack at http://localstack:4566Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3, Service.SQS, Service.DYNAMODB);
localstack.start();
// Frontend service
GenericContainer<?> frontend = new GenericContainer<>("frontend:latest")
.withNetwork(network)
.withEnv("AWS_ENDPOINT", "http://localstack:4566")
.withEnv("AWS_REGION", localstack.getRegion())
.withExposedPorts(3000);
// Backend service
GenericContainer<?> backend = new GenericContainer<>("backend:latest")
.withNetwork(network)
.withEnv("AWS_ENDPOINT", "http://localstack:4566")
.withEnv("AWS_ACCESS_KEY_ID", localstack.getAccessKey())
.withEnv("AWS_SECRET_ACCESS_KEY", localstack.getSecretKey())
.withEnv("AWS_REGION", localstack.getRegion())
.withExposedPorts(8080);
frontend.start();
backend.start();
// Both frontend and backend can access LocalStackRun AWS CLI commands from within the Docker network:
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Container.ExecResult;
Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3, Service.SQS);
localstack.start();
// AWS CLI container
GenericContainer<?> awsCli = new GenericContainer<>("amazon/aws-cli:latest")
.withNetwork(network)
.withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("tail"))
.withCommand("-f /dev/null")
.withEnv("AWS_ACCESS_KEY_ID", localstack.getAccessKey())
.withEnv("AWS_SECRET_ACCESS_KEY", localstack.getSecretKey())
.withEnv("AWS_REGION", localstack.getRegion());
awsCli.start();
// Execute AWS CLI commands
ExecResult result = awsCli.execInContainer(
"aws", "s3", "mb", "s3://test-bucket",
"--endpoint-url", "http://localstack:4566"
);
System.out.println("Exit code: " + result.getExitCode());
System.out.println("Output: " + result.getStdout());
// List buckets
ExecResult listResult = awsCli.execInContainer(
"aws", "s3", "ls",
"--endpoint-url", "http://localstack:4566"
);
System.out.println("Buckets: " + listResult.getStdout());LocalStack automatically configures the external hostname based on the network setup:
Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(
DockerImageName.parse("localstack/localstack:2.0")
)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.SQS);
localstack.start();
// For LocalStack 2.0+, LOCALSTACK_HOST is set
String localstackHost = localstack.getEnvMap().get("LOCALSTACK_HOST");
System.out.println("LOCALSTACK_HOST: " + localstackHost); // "localstack"
// For older versions
LocalStackContainer legacyLocalstack = new LocalStackContainer(
DockerImageName.parse("localstack/localstack:0.12")
)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.SQS);
legacyLocalstack.start();
String hostnameExternal = legacyLocalstack.getEnvMap().get("HOSTNAME_EXTERNAL");
System.out.println("HOSTNAME_EXTERNAL: " + hostnameExternal); // "localstack"Network network = Network.newNetwork();
// Override the hostname manually
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("myalias")
.withEnv("LOCALSTACK_HOST", "custom-hostname")
.withServices(Service.S3);
localstack.start();
String hostname = localstack.getEnvMap().get("LOCALSTACK_HOST");
System.out.println("Custom hostname: " + hostname); // "custom-hostname"When using SQS within a Docker network, queue URLs will contain the network alias:
import software.amazon.awssdk.services.sqs.SqsClient;
Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.SQS);
localstack.start();
// Create SQS client (from host)
SqsClient sqs = SqsClient.builder()
.endpointOverride(localstack.getEndpoint())
.credentialsProvider(
StaticCredentialsProvider.create(
AwsBasicCredentials.create(
localstack.getAccessKey(),
localstack.getSecretKey()
)
)
)
.region(Region.of(localstack.getRegion()))
.build();
// Create queue
String queueUrl = sqs.createQueue(q -> q.queueName("test-queue"))
.queueUrl();
System.out.println("Queue URL: " + queueUrl);
// Output: http://localstack:4566/000000000000/test-queue
// The queue URL contains the network alias "localstack"
// This URL works from containers within the networkWithout specifying a network, LocalStack runs on the default bridge network and is exposed to the host:
// No network configuration - uses bridge network
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withServices(Service.S3);
localstack.start();
// Access from host
URI endpoint = localstack.getEndpoint();
System.out.println("Endpoint: " + endpoint);
// Output: http://192.168.1.100:49153 (host IP and mapped port)
// Not accessible to other containers by defaultWith a custom network, LocalStack can communicate with other containers:
Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3);
localstack.start();
// Access from host (still uses mapped port)
URI endpoint = localstack.getEndpoint();
System.out.println("Host endpoint: " + endpoint);
// Output: http://192.168.1.100:49153
// Access from containers within the network
System.out.println("Network endpoint: http://localstack:4566");import org.testcontainers.containers.Network;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.containers.localstack.LocalStackContainer.Service;
import org.testcontainers.utility.DockerImageName;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
@Testcontainers
public class NetworkIntegrationTest {
// Shared network
private static final Network network = Network.newNetwork();
@Container
static LocalStackContainer localstack = new LocalStackContainer(
DockerImageName.parse("localstack/localstack:2.0")
)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3, Service.SQS, Service.DYNAMODB);
@Container
static GenericContainer<?> app = new GenericContainer<>("myapp:latest")
.withNetwork(network)
.withEnv("AWS_ENDPOINT", "http://localstack:4566")
.withEnv("AWS_ACCESS_KEY_ID", "test")
.withEnv("AWS_SECRET_ACCESS_KEY", "test")
.withEnv("AWS_REGION", "us-east-1")
.withExposedPorts(8080)
.dependsOn(localstack);
@Test
void testAppCanAccessLocalStack() {
// From the test (running on host), use getEndpoint()
S3Client s3 = S3Client.builder()
.endpointOverride(localstack.getEndpoint())
.credentialsProvider(
StaticCredentialsProvider.create(
AwsBasicCredentials.create(
localstack.getAccessKey(),
localstack.getSecretKey()
)
)
)
.region(Region.of(localstack.getRegion()))
.build();
// Create a bucket
s3.createBucket(b -> b.bucket("test-bucket"));
// The app container can also access this bucket at http://localstack:4566
// Make HTTP request to app container and verify it can interact with S3
String appUrl = "http://" + app.getHost() + ":" + app.getMappedPort(8080);
// ... test app endpoints that use LocalStack
}
}LocalStack automatically configures Docker labels for spawned Lambda and ECS containers to ensure proper cleanup:
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withServices(Service.LAMBDA);
localstack.start();
// When Lambda functions are invoked, LocalStack spawns containers
// These containers are automatically labeled with Testcontainers labels
// This ensures they are cleaned up when the LocalStack container stops
// The labels include:
// - org.testcontainers=true
// - org.testcontainers.sessionId=<session-id>
// - org.testcontainers.version=<version>
// This is handled automatically via environment variables:
// LAMBDA_DOCKER_FLAGS, ECS_DOCKER_FLAGS, EC2_DOCKER_FLAGS, BATCH_DOCKER_FLAGSNetworks are automatically cleaned up when containers stop:
Network network = Network.newNetwork();
try {
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3);
localstack.start();
// Use LocalStack
// ...
localstack.stop();
} finally {
// Clean up network
network.close();
}
// With JUnit 5 and @Testcontainers, cleanup is automaticProblem: Application container cannot connect to LocalStack.
Solutions:
localstack.withNetwork(network) and app.withNetwork(network)http://localstack:4566 (not getEndpoint())localstack.withNetworkAliases("localstack")// CORRECT
Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack") // Set alias
.withServices(Service.S3);
localstack.start();
GenericContainer<?> app = new GenericContainer<>("myapp:latest")
.withNetwork(network) // Same network
.withEnv("AWS_ENDPOINT", "http://localstack:4566"); // Use aliasProblem: Network alias not resolving in containers.
Solutions:
// Verify hostname configuration
localstack.start();
String hostname = localstack.getEnvMap().get("LOCALSTACK_HOST");
System.out.println("Hostname: " + hostname); // Should be "localstack"Problem: Using wrong endpoint format for network communication.
Solutions:
localstack.getEndpoint() (returns IP address)http://localstack:4566 (not getEndpoint())localhost in network endpoints// WRONG - from container
String endpoint = localstack.getEndpoint().toString(); // IP address
app.withEnv("AWS_ENDPOINT", endpoint); // May not work in network
// CORRECT - from container
app.withEnv("AWS_ENDPOINT", "http://localstack:4566"); // Use aliasProblem: Network not cleaned up after tests.
Solutions:
@Testcontainers for automatic cleanupnetwork.close()Network network = Network.newNetwork();
try {
// ... use network
} finally {
network.close(); // Clean up
}Network network = Network.newNetwork();
LocalStackContainer localstack = new LocalStackContainer(dockerImageName)
.withNetwork(network)
.withNetworkAliases("localstack")
.withServices(Service.S3);
localstack.start();
// Check network aliases
List<String> aliases = localstack.getNetworkAliases();
System.out.println("Network aliases: " + aliases);
// Check hostname environment variables
Map<String, String> env = localstack.getEnvMap();
System.out.println("HOSTNAME_EXTERNAL: " + env.get("HOSTNAME_EXTERNAL"));
System.out.println("LOCALSTACK_HOST: " + env.get("LOCALSTACK_HOST"));
// Check network ID
String networkId = localstack.getNetwork().getId();
System.out.println("Network ID: " + networkId);// From application container, test connectivity
GenericContainer<?> app = new GenericContainer<>("curlimages/curl:latest")
.withNetwork(network)
.withCommand("curl", "-v", "http://localstack:4566/_localstack/health");
app.start();
String logs = app.getLogs();
System.out.println("Health check result: " + logs);// From host
URI hostEndpoint = localstack.getEndpoint();
System.out.println("Host endpoint: " + hostEndpoint);
// From network (should use alias)
String networkEndpoint = "http://localstack:4566";
System.out.println("Network endpoint: " + networkEndpoint);
// Test from host
S3Client s3 = S3Client.builder()
.endpointOverride(hostEndpoint) // Use host endpoint
.build();
// Test from container (would use network endpoint)
// app.withEnv("AWS_ENDPOINT", networkEndpoint);