diff --git a/test/deps.go b/test/deps.go
index 0904ee326020fe7ccce38cbc4bdf6e00b70e684b..611f1bb935a1ea1209ce5bf335da1e799003b8f7 100644
--- a/test/deps.go
+++ b/test/deps.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"log"
+	"os"
 	"path"
 	"time"
 
@@ -18,17 +19,24 @@ type ContainerDeps struct {
 	redisContainer testcontainers.Container
 	homeservers    []*SynapseDep
 	machines       []*mmrContainer
+	depNet         *NetworkDep
 }
 
 func MakeTestDeps() (*ContainerDeps, error) {
 	ctx := context.Background()
 
+	// Create a network
+	depNet, err := MakeNetwork()
+	if err != nil {
+		return nil, err
+	}
+
 	// Start two synapses for testing
-	syn1, err := MakeSynapse("first.example.org")
+	syn1, err := MakeSynapse("first.example.org", depNet)
 	if err != nil {
 		return nil, err
 	}
-	syn2, err := MakeSynapse("second.example.org")
+	syn2, err := MakeSynapse("second.example.org", depNet)
 	if err != nil {
 		return nil, err
 	}
@@ -39,6 +47,7 @@ func MakeTestDeps() (*ContainerDeps, error) {
 		postgres.WithDatabase("mmr"),
 		postgres.WithUsername("postgres"),
 		postgres.WithPassword("test1234"),
+		depNet.ApplyToContainer(),
 		testcontainers.WithWaitStrategy(
 			wait.ForLog("database system is ready to accept connections").WithOccurrence(2).WithStartupTimeout(5*time.Second)),
 	)
@@ -51,31 +60,32 @@ func MakeTestDeps() (*ContainerDeps, error) {
 	}
 
 	// Start a redis container
+	cwd, err := os.Getwd()
+	if err != nil {
+		return nil, err
+	}
 	redisContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
 		ContainerRequest: testcontainers.ContainerRequest{
 			Image:        "docker.io/library/redis:7",
 			ExposedPorts: []string{"6379/tcp"},
 			Mounts: []testcontainers.ContainerMount{
-				testcontainers.BindMount(path.Join(".", "dev", "redis.conf"), "/usr/local/etc/redis/redis.conf"),
+				testcontainers.BindMount(path.Join(cwd, ".", "dev", "redis.conf"), "/usr/local/etc/redis/redis.conf"),
 			},
-			Cmd: []string{"redis-server", "/usr/local/etc/redis/redis.conf"},
+			Cmd:      []string{"redis-server", "/usr/local/etc/redis/redis.conf"},
+			Networks: []string{depNet.NetId},
 		},
 		Started: true,
 	})
 	if err != nil {
 		return nil, err
 	}
-	redisHost, err := redisContainer.Host(ctx)
-	if err != nil {
-		return nil, err
-	}
-	redisPort, err := redisContainer.MappedPort(ctx, "6379/tcp")
+	redisHost, err := redisContainer.ContainerIP(ctx)
 	if err != nil {
 		return nil, err
 	}
 
 	// Start two MMRs for testing
-	mmrs, err := makeMmrInstances(ctx, 2, mmrTmplArgs{
+	mmrs, err := makeMmrInstances(ctx, 2, depNet, mmrTmplArgs{
 		Homeservers: []mmrHomeserverTmplArgs{
 			{
 				ServerName:         syn1.ServerName,
@@ -86,7 +96,7 @@ func MakeTestDeps() (*ContainerDeps, error) {
 				ClientServerApiUrl: syn2.ClientServerApiUrl,
 			},
 		},
-		RedisAddr:          fmt.Sprintf("%s:%d", redisHost, redisPort.Int()),
+		RedisAddr:          fmt.Sprintf("%s:%d", redisHost, 6379), // we're behind the network for redis
 		PgConnectionString: pgConnStr,
 	})
 
@@ -96,6 +106,7 @@ func MakeTestDeps() (*ContainerDeps, error) {
 		redisContainer: redisContainer,
 		homeservers:    []*SynapseDep{syn1, syn2},
 		machines:       mmrs,
+		depNet:         depNet,
 	}, nil
 }
 
@@ -112,4 +123,5 @@ func (c *ContainerDeps) Teardown() {
 	if err := c.pgContainer.Terminate(c.ctx); err != nil {
 		log.Fatalf("Error shutting down mmr-postgres container: %s", err.Error())
 	}
+	c.depNet.Teardown()
 }
diff --git a/test/deps_mmr.go b/test/deps_mmr.go
index 2d1e1ae830ac78fff5e0c182cb9ad04021f12edf..5e6a76148aa3749b0ce871d81430f4f46db9dba9 100644
--- a/test/deps_mmr.go
+++ b/test/deps_mmr.go
@@ -10,6 +10,7 @@ import (
 	"strings"
 	"text/template"
 
+	"github.com/docker/go-connections/nat"
 	"github.com/testcontainers/testcontainers-go"
 	"github.com/testcontainers/testcontainers-go/wait"
 )
@@ -34,7 +35,7 @@ type mmrContainer struct {
 	MachineId int
 }
 
-func makeMmrInstances(ctx context.Context, count int, tmplArgs mmrTmplArgs) ([]*mmrContainer, error) {
+func makeMmrInstances(ctx context.Context, count int, depNet *NetworkDep, tmplArgs mmrTmplArgs) ([]*mmrContainer, error) {
 	// Prepare a config template
 	t, err := template.New("mmr.config.yaml").ParseFiles(path.Join(".", "test", "templates", "mmr.config.yaml"))
 	if err != nil {
@@ -64,6 +65,7 @@ func makeMmrInstances(ctx context.Context, count int, tmplArgs mmrTmplArgs) ([]*
 	mmrs := make([]*mmrContainer, 0)
 	for i := 0; i < count; i++ {
 		// Create the docker container (from dockerfile)
+		p, _ := nat.NewPort("tcp", "8000")
 		container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
 			ContainerRequest: testcontainers.ContainerRequest{
 				FromDockerfile: testcontainers.FromDockerfile{
@@ -76,7 +78,8 @@ func makeMmrInstances(ctx context.Context, count int, tmplArgs mmrTmplArgs) ([]*
 				Env: map[string]string{
 					"MACHINE_ID": strconv.Itoa(i),
 				},
-				WaitingFor: wait.ForHTTP("/healthz"),
+				Networks:   []string{depNet.NetId},
+				WaitingFor: wait.ForHTTP("/healthz").WithPort(p),
 			},
 			Started: true,
 		})
diff --git a/test/deps_network.go b/test/deps_network.go
new file mode 100644
index 0000000000000000000000000000000000000000..b9495cf4c9ba19c2257e5af79741cbf93e84f270
--- /dev/null
+++ b/test/deps_network.go
@@ -0,0 +1,62 @@
+package test
+
+import (
+	"context"
+	"log"
+
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/turt2live/matrix-media-repo/util/ids"
+)
+
+type NetworkDep struct {
+	ctx       context.Context
+	dockerNet testcontainers.Network
+
+	NetId string
+}
+
+type netCustomizer struct {
+	testcontainers.ContainerCustomizer
+	network *NetworkDep
+}
+
+func (c *netCustomizer) Customize(req *testcontainers.GenericContainerRequest) {
+	if req.Networks == nil {
+		req.Networks = make([]string, 0)
+	}
+	req.Networks = append(req.Networks, c.network.NetId)
+}
+
+func MakeNetwork() (*NetworkDep, error) {
+	ctx := context.Background()
+
+	netId, err := ids.NewUniqueId()
+	if err != nil {
+		return nil, err
+	}
+	dockerNet, err := testcontainers.GenericNetwork(ctx, testcontainers.GenericNetworkRequest{
+		NetworkRequest: testcontainers.NetworkRequest{
+			Name: netId,
+		},
+		ProviderType: testcontainers.ProviderDocker,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return &NetworkDep{
+		ctx:       ctx,
+		dockerNet: dockerNet,
+		NetId:     netId,
+	}, nil
+}
+
+func (n *NetworkDep) ApplyToContainer() testcontainers.ContainerCustomizer {
+	return &netCustomizer{network: n}
+}
+
+func (n *NetworkDep) Teardown() {
+	if err := n.dockerNet.Remove(n.ctx); err != nil {
+		log.Fatalf("Error cleaning up docker network '%s': %s", n.NetId, err.Error())
+	}
+}
diff --git a/test/deps_synapse.go b/test/deps_synapse.go
index 2035cf2c377369b2aa6b00cad7687e672678c4e3..9ef346056ba4f2b03fbed1a93807e9bf8c59efd3 100644
--- a/test/deps_synapse.go
+++ b/test/deps_synapse.go
@@ -32,7 +32,16 @@ type SynapseDep struct {
 	ServerName         string
 }
 
-func MakeSynapse(domainName string) (*SynapseDep, error) {
+type fixNetwork struct {
+	testcontainers.ContainerCustomizer
+	NetId string
+}
+
+func (f *fixNetwork) Customize(req *testcontainers.GenericContainerRequest) {
+	req.Networks = []string{f.NetId}
+}
+
+func MakeSynapse(domainName string, depNet *NetworkDep) (*SynapseDep, error) {
 	ctx := context.Background()
 
 	// Start postgresql database
@@ -41,6 +50,8 @@ func MakeSynapse(domainName string) (*SynapseDep, error) {
 		postgres.WithDatabase("synapse"),
 		postgres.WithUsername("postgres"),
 		postgres.WithPassword("test1234"),
+		WithEnvironment("POSTGRES_INITDB_ARGS", "--encoding=UTF8 --locale=C"),
+		depNet.ApplyToContainer(),
 		testcontainers.WithWaitStrategy(
 			wait.ForLog("database system is ready to accept connections").WithOccurrence(2).WithStartupTimeout(5*time.Second)),
 	)
@@ -57,15 +68,11 @@ func MakeSynapse(domainName string) (*SynapseDep, error) {
 	if err != nil {
 		return nil, err
 	}
-	pgport, err := pgContainer.MappedPort(ctx, "5432/tcp")
-	if err != nil {
-		return nil, err
-	}
 	w := new(strings.Builder)
 	err = t.Execute(w, synapseTmplArgs{
 		ServerName: domainName,
 		PgHost:     pghost,
-		PgPort:     pgport.Int(),
+		PgPort:     5432, // we're behind the network here
 	})
 	if err != nil {
 		return nil, err
@@ -105,6 +112,7 @@ func MakeSynapse(domainName string) (*SynapseDep, error) {
 				testcontainers.BindMount(d, "/app"),
 			},
 			WaitingFor: wait.ForHTTP("/health").WithPort(p),
+			Networks:   []string{depNet.NetId},
 		},
 		Started: true,
 	})
@@ -113,7 +121,7 @@ func MakeSynapse(domainName string) (*SynapseDep, error) {
 	}
 
 	// Prepare the CS API URL
-	synHost, err := synContainer.Host(ctx)
+	synHost, err := synContainer.ContainerIP(ctx)
 	if err != nil {
 		return nil, err
 	}
diff --git a/test/testcontainers_ext.go b/test/testcontainers_ext.go
new file mode 100644
index 0000000000000000000000000000000000000000..3fccb7fa225a68c8d4d53f070c8204c68d1d175c
--- /dev/null
+++ b/test/testcontainers_ext.go
@@ -0,0 +1,23 @@
+package test
+
+import "github.com/testcontainers/testcontainers-go"
+
+type EnvCustomizer struct {
+	testcontainers.ContainerCustomizer
+	varName  string
+	varValue string
+}
+
+func WithEnvironment(name string, value string) *EnvCustomizer {
+	return &EnvCustomizer{
+		varName:  name,
+		varValue: value,
+	}
+}
+
+func (c *EnvCustomizer) Customize(req *testcontainers.GenericContainerRequest) {
+	if req.Env == nil {
+		req.Env = make(map[string]string)
+	}
+	req.Env[c.varName] = c.varValue
+}