diff --git a/.gitignore b/.gitignore
index c5425e5..c3b5d86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-/octoplex.log
+*.log
 /mediamtx.yml
diff --git a/container/container.go b/container/container.go
index a07ea53..370f232 100644
--- a/container/container.go
+++ b/container/container.go
@@ -185,7 +185,7 @@ func (a *Client) RunContainer(ctx context.Context, params RunContainerParams) (<
 			sendError(fmt.Errorf("container create: %w", err))
 			return
 		}
-		containerStateC <- domain.Container{ID: createResp.ID, State: "created"}
+		containerStateC <- domain.Container{ID: createResp.ID, Status: domain.ContainerStatusCreated}
 
 		if err = a.apiClient.NetworkConnect(ctx, a.networkID, createResp.ID, nil); err != nil {
 			sendError(fmt.Errorf("network connect: %w", err))
@@ -198,7 +198,7 @@ func (a *Client) RunContainer(ctx context.Context, params RunContainerParams) (<
 		}
 		a.logger.Info("Started container", "id", shortID(createResp.ID), "duration", time.Since(now))
 
-		containerStateC <- domain.Container{ID: createResp.ID, State: "running"}
+		containerStateC <- domain.Container{ID: createResp.ID, Status: domain.ContainerStatusRunning}
 
 		a.runContainerLoop(ctx, createResp.ID, params.NetworkCountConfig, containerStateC, errC)
 	}()
@@ -216,7 +216,7 @@ func (a *Client) pullImageIfNeeded(ctx context.Context, imageName string, contai
 		return nil
 	}
 
-	containerStateC <- domain.Container{State: "pulling"}
+	containerStateC <- domain.Container{Status: domain.ContainerStatusPulling}
 
 	pullReader, err := a.apiClient.ImagePull(ctx, imageName, image.PullOptions{})
 	if err != nil {
@@ -292,7 +292,7 @@ func (a *Client) runContainerLoop(
 		}
 	}()
 
-	state := &domain.Container{ID: containerID, State: "running"}
+	state := &domain.Container{ID: containerID, Status: domain.ContainerStatusRunning}
 	sendState := func() { stateC <- *state }
 	sendState()
 
@@ -308,7 +308,7 @@ func (a *Client) runContainerLoop(
 				containerState = "exited"
 			}
 
-			state.State = containerState
+			state.Status = containerState
 			state.CPUPercent = 0
 			state.MemoryUsageBytes = 0
 			state.HealthState = "unhealthy"
@@ -338,7 +338,7 @@ func (a *Client) runContainerLoop(
 			}
 
 			if evt.Action == "start" {
-				state.State = "running"
+				state.Status = domain.ContainerStatusRunning
 				sendState()
 				continue
 			}
diff --git a/container/container_test.go b/container/container_test.go
index 53a9588..544767c 100644
--- a/container/container_test.go
+++ b/container/container_test.go
@@ -89,10 +89,10 @@ func TestClientRunContainer(t *testing.T) {
 		require.NoError(t, <-errC)
 	}()
 
-	assert.Equal(t, "pulling", (<-containerStateC).State)
-	assert.Equal(t, "created", (<-containerStateC).State)
-	assert.Equal(t, "running", (<-containerStateC).State)
-	assert.Equal(t, "running", (<-containerStateC).State)
+	assert.Equal(t, "pulling", (<-containerStateC).Status)
+	assert.Equal(t, "created", (<-containerStateC).Status)
+	assert.Equal(t, "running", (<-containerStateC).Status)
+	assert.Equal(t, "running", (<-containerStateC).Status)
 
 	// Enough time for events channel to receive a message:
 	time.Sleep(100 * time.Millisecond)
@@ -100,7 +100,7 @@ func TestClientRunContainer(t *testing.T) {
 	containerWaitC <- dockercontainer.WaitResponse{StatusCode: 1}
 
 	state := <-containerStateC
-	assert.Equal(t, "exited", state.State)
+	assert.Equal(t, "exited", state.Status)
 	assert.Equal(t, "unhealthy", state.HealthState)
 	require.NotNil(t, state.ExitCode)
 	assert.Equal(t, 1, *state.ExitCode)
@@ -146,8 +146,8 @@ func TestClientRunContainerErrorStartingContainer(t *testing.T) {
 		HostConfig:      &dockercontainer.HostConfig{},
 	})
 
-	assert.Equal(t, "pulling", (<-containerStateC).State)
-	assert.Equal(t, "created", (<-containerStateC).State)
+	assert.Equal(t, "pulling", (<-containerStateC).Status)
+	assert.Equal(t, "created", (<-containerStateC).Status)
 
 	err = <-errC
 	require.EqualError(t, err, "container start: error starting container")
diff --git a/container/integration_test.go b/container/integration_test.go
index 3595507..c81dd59 100644
--- a/container/integration_test.go
+++ b/container/integration_test.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"git.netflux.io/rob/octoplex/container"
+	"git.netflux.io/rob/octoplex/domain"
 	"git.netflux.io/rob/octoplex/shortid"
 	"git.netflux.io/rob/octoplex/testhelpers"
 	typescontainer "github.com/docker/docker/api/types/container"
@@ -196,11 +197,11 @@ func TestContainerRestart(t *testing.T) {
 	testhelpers.ChanRequireNoError(t, errC)
 
 	containerState := <-containerStateC
-	assert.Equal(t, "pulling", containerState.State)
+	assert.Equal(t, "pulling", containerState.Status)
 	containerState = <-containerStateC
-	assert.Equal(t, "created", containerState.State)
+	assert.Equal(t, "created", containerState.Status)
 	containerState = <-containerStateC
-	assert.Equal(t, "running", containerState.State)
+	assert.Equal(t, "running", containerState.Status)
 
 	err = nil // reset error
 	done := make(chan struct{})
@@ -210,9 +211,9 @@ func TestContainerRestart(t *testing.T) {
 		var count int
 		for {
 			containerState = <-containerStateC
-			if containerState.State == "restarting" {
+			if containerState.Status == domain.ContainerStatusRestarting {
 				break
-			} else if containerState.State == "exited" {
+			} else if containerState.Status == domain.ContainerStatusExited {
 				err = errors.New("container exited unexpectedly")
 			} else if count >= 5 {
 				err = errors.New("container did not enter restarting state")
diff --git a/domain/types.go b/domain/types.go
index 32c2938..d19da79 100644
--- a/domain/types.go
+++ b/domain/types.go
@@ -55,13 +55,24 @@ type Destination struct {
 	URL       string
 }
 
-// Container represents the current state of an individual container.
+// Container status strings.
 //
-// The source of truth is always the Docker daemon, this struct is used only
-// for passing asynchronous state.
+// TODO: refactor to strictly reflect Docker status strings.
+const (
+	ContainerStatusPulling    = "pulling" // Does not correspond to a Docker status.
+	ContainerStatusCreated    = "created"
+	ContainerStatusRunning    = "running"
+	ContainerStatusPaused     = "paused"
+	ContainerStatusRestarting = "restarting"
+	ContainerStatusRemoving   = "removing"
+	ContainerStatusExited     = "exited"
+	ContainerStatusDead       = "dead"
+)
+
+// Container represents the current state of an individual container.
 type Container struct {
 	ID               string
-	State            string
+	Status           string
 	HealthState      string
 	CPUPercent       float64
 	MemoryUsageBytes uint64
diff --git a/mediaserver/actor.go b/mediaserver/actor.go
index 76c6b52..80cc132 100644
--- a/mediaserver/actor.go
+++ b/mediaserver/actor.go
@@ -172,7 +172,7 @@ func (s *Actor) actorLoop(containerStateC <-chan domain.Container, errC <-chan e
 		case containerState := <-containerStateC:
 			s.state.Container = containerState
 
-			if s.state.Container.State == "exited" {
+			if s.state.Container.Status == domain.ContainerStatusExited {
 				fetchStateT.Stop()
 				s.handleContainerExit(nil)
 			}
diff --git a/multiplexer/multiplexer.go b/multiplexer/multiplexer.go
index ea076e5..f006eb5 100644
--- a/multiplexer/multiplexer.go
+++ b/multiplexer/multiplexer.go
@@ -146,7 +146,7 @@ func (a *Actor) destLoop(url string, containerStateC <-chan domain.Container, er
 		case containerState := <-containerStateC:
 			state.Container = containerState
 
-			if containerState.State == "running" {
+			if containerState.Status == "running" {
 				if hasElapsedSince(5*time.Second, containerState.RxSince) {
 					state.Status = domain.DestinationStatusLive
 				} else {
diff --git a/terminal/terminal.go b/terminal/terminal.go
index dd7cfd9..a8abb1d 100644
--- a/terminal/terminal.go
+++ b/terminal/terminal.go
@@ -326,7 +326,7 @@ func (ui *UI) redrawFromState(state domain.AppState) {
 		}
 
 		ui.sourceViews.status.SetText("[black:green]receiving" + durStr)
-	} else if state.Source.Container.State == "running" && state.Source.Container.HealthState == "healthy" {
+	} else if state.Source.Container.Status == domain.ContainerStatusRunning && state.Source.Container.HealthState == "healthy" {
 		ui.sourceViews.status.SetText("[black:yellow]ready")
 	} else {
 		ui.sourceViews.status.SetText("[white:red]not ready")
@@ -335,19 +335,19 @@ func (ui *UI) redrawFromState(state domain.AppState) {
 	ui.sourceViews.health.SetText("[white]" + cmp.Or(rightPad(state.Source.Container.HealthState, 9), dash))
 
 	cpuPercent := dash
-	if state.Source.Container.State == "running" {
+	if state.Source.Container.Status == domain.ContainerStatusRunning {
 		cpuPercent = fmt.Sprintf("%.1f", state.Source.Container.CPUPercent)
 	}
 	ui.sourceViews.cpu.SetText("[white]" + cpuPercent)
 
 	memUsage := dash
-	if state.Source.Container.State == "running" {
+	if state.Source.Container.Status == domain.ContainerStatusRunning {
 		memUsage = fmt.Sprintf("%.1f", float64(state.Source.Container.MemoryUsageBytes)/1024/1024)
 	}
 	ui.sourceViews.mem.SetText("[white]" + memUsage)
 
 	rxRate := dash
-	if state.Source.Container.State == "running" {
+	if state.Source.Container.Status == domain.ContainerStatusRunning {
 		rxRate = fmt.Sprintf("%d", state.Source.Container.RxRate)
 	}
 	ui.sourceViews.rx.SetText("[white]" + rxRate)
@@ -385,7 +385,7 @@ func (ui *UI) redrawFromState(state domain.AppState) {
 			ui.destView.SetCell(i+1, 2, tview.NewTableCell("[white]"+rightPad("off-air", statusLen)))
 		}
 
-		ui.destView.SetCell(i+1, 3, tview.NewTableCell("[white]"+rightPad(cmp.Or(dest.Container.State, dash), 10)))
+		ui.destView.SetCell(i+1, 3, tview.NewTableCell("[white]"+rightPad(cmp.Or(dest.Container.Status, dash), 10)))
 
 		healthState := dash
 		if dest.Status == domain.DestinationStatusLive {
@@ -394,19 +394,19 @@ func (ui *UI) redrawFromState(state domain.AppState) {
 		ui.destView.SetCell(i+1, 4, tview.NewTableCell("[white]"+rightPad(healthState, 7)))
 
 		cpuPercent := dash
-		if dest.Container.State == "running" {
+		if dest.Container.Status == domain.ContainerStatusRunning {
 			cpuPercent = fmt.Sprintf("%.1f", dest.Container.CPUPercent)
 		}
 		ui.destView.SetCell(i+1, 5, tview.NewTableCell("[white]"+rightPad(cpuPercent, 4)))
 
 		memoryUsage := dash
-		if dest.Container.State == "running" {
+		if dest.Container.Status == domain.ContainerStatusRunning {
 			memoryUsage = fmt.Sprintf("%.1f", float64(dest.Container.MemoryUsageBytes)/1000/1000)
 		}
 		ui.destView.SetCell(i+1, 6, tview.NewTableCell("[white]"+rightPad(memoryUsage, 4)))
 
 		txRate := dash
-		if dest.Container.State == "running" {
+		if dest.Container.Status == domain.ContainerStatusRunning {
 			txRate = "[white]" + rightPad(strconv.Itoa(dest.Container.TxRate), 4)
 		}
 		ui.destView.SetCell(i+1, 7, tview.NewTableCell(txRate))