Skip to main content
Viber includes Docker support for containerized deployment. This guide covers building and running Viber with Docker.

Quick start

The fastest way to run Viber with Docker:
./docker.sh
This convenience script builds the image, manages containers, and tests API routes automatically.

Manual Docker setup

For more control over the Docker build and run process:
1

Build the Docker image

docker build -t viber .
This builds the production image using the multi-stage Dockerfile.
2

Run the container

docker run --rm -p 3000:3000 \
  -e GEMINI_API_KEY=your_key \
  -e DAYTONA_API_KEY=your_key \
  -e UNSPLASH_ACCESS_KEY=your_key \
  -e UNSPLASH_SECRET_KEY=your_key \
  viber
3

Access the application

Open your browser to:
http://localhost:3000

Understanding the Dockerfile

Viber uses a multi-stage Dockerfile for optimized builds:

Stage 1: Base image

Dockerfile:1-2
FROM oven/bun:1 AS base
WORKDIR /app
Uses the official Bun runtime image as the foundation.

Stage 2: Install dependencies

Dockerfile:4-7
FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lock* /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile
Installs dependencies in isolation for better caching.

Stage 3: Build application

Dockerfile:9-15
FROM base AS prerelease
COPY --from=install /temp/dev/node_modules node_modules
COPY . .

ENV NODE_ENV=production
ENV VITE_ELEVENLABS_AGENT_ID=agent_5901kch85sfye06s56m7kshw9kf4
RUN rm -rf .output && bun run build
The VITE_ELEVENLABS_AGENT_ID is hardcoded in the Dockerfile. To use your own agent ID, modify this value before building or use a build argument.

Stage 4: Production runtime

Dockerfile:17-27
FROM base AS release
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=3000

COPY --from=prerelease /app/.output /app/.output
COPY --from=prerelease /app/public /app/public

EXPOSE 3000

CMD ["bun", "--bun", ".output/server/index.mjs"]
The final stage contains only the built application and necessary runtime files.

Environment variables

Required variables

docker run --rm -p 3000:3000 \
  -e GEMINI_API_KEY=your_gemini_api_key \
  -e DAYTONA_API_KEY=your_daytona_api_key \
  -e UNSPLASH_ACCESS_KEY=your_unsplash_access_key \
  -e UNSPLASH_SECRET_KEY=your_unsplash_secret_key \
  viber

Optional variables

Add optional configuration:
docker run --rm -p 3000:3000 \
  -e GEMINI_API_KEY=your_key \
  -e DAYTONA_API_KEY=your_key \
  -e UNSPLASH_ACCESS_KEY=your_key \
  -e UNSPLASH_SECRET_KEY=your_key \
  -e ELEVENLABS_API_KEY=your_elevenlabs_key \
  -e DEFAULT_MODEL=gemini-2.5-pro \
  -e IMAGE_CDN_BASE_URL=https://your-domain.com \
  viber

Using an environment file

For easier management, create a .env.docker file:
.env.docker
GEMINI_API_KEY=your_gemini_api_key
DAYTONA_API_KEY=your_daytona_api_key
UNSPLASH_ACCESS_KEY=your_unsplash_access_key
UNSPLASH_SECRET_KEY=your_unsplash_secret_key
ELEVENLABS_API_KEY=your_elevenlabs_api_key
DEFAULT_MODEL=gemini-2.5-pro
IMAGE_CDN_BASE_URL=https://your-domain.com
Then run with:
docker run --rm -p 3000:3000 --env-file .env.docker viber
Add .env.docker to your .gitignore to avoid committing sensitive credentials.

The convenience script

The included docker.sh script automates the build and run process:
docker.sh:1-20
#!/bin/bash

set -e

CONTAINER_NAME="viber"
IMAGE_NAME="viber"
PORT=${PORT:-3000}

echo "πŸ”¨ Building Docker image..."
docker build -t $IMAGE_NAME .

echo "πŸ›‘ Stopping and removing existing container (if any)..."
docker stop $CONTAINER_NAME 2>/dev/null || true
docker rm $CONTAINER_NAME 2>/dev/null || true

echo "πŸš€ Starting new container..."
docker run -d \
  --name $CONTAINER_NAME \
  -p $PORT:3000 \
  $IMAGE_NAME

What the script does

1

Builds the image

Runs docker build -t viber .
2

Cleans up existing containers

Stops and removes any existing container named β€œviber”
3

Starts the container

Launches a new container in detached mode on port 3000
4

Tests API routes

Verifies the application is running by testing /api/test and /api/health endpoints

Customizing the script

Override the port:
PORT=8080 ./docker.sh
To add environment variables to the script, modify the docker run command:
docker.sh
docker run -d \
  --name $CONTAINER_NAME \
  -p $PORT:3000 \
  -e GEMINI_API_KEY=your_key \
  -e DAYTONA_API_KEY=your_key \
  --env-file .env.docker \
  $IMAGE_NAME

Container management

View logs

docker logs -f viber

Stop the container

docker stop viber

Remove the container

docker rm viber

List running containers

docker ps

Execute commands in the container

docker exec -it viber /bin/bash

Docker Compose

For a complete Docker Compose setup, create a docker-compose.yml:
docker-compose.yml
version: '3.8'

services:
  viber:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - GEMINI_API_KEY=${GEMINI_API_KEY}
      - DAYTONA_API_KEY=${DAYTONA_API_KEY}
      - UNSPLASH_ACCESS_KEY=${UNSPLASH_ACCESS_KEY}
      - UNSPLASH_SECRET_KEY=${UNSPLASH_SECRET_KEY}
      - ELEVENLABS_API_KEY=${ELEVENLABS_API_KEY}
      - DEFAULT_MODEL=${DEFAULT_MODEL:-gemini-3-pro}
      - IMAGE_CDN_BASE_URL=${IMAGE_CDN_BASE_URL}
    restart: unless-stopped
Run with:
docker-compose up -d

Troubleshooting

Container exits immediately

The application requires GEMINI_API_KEY, DAYTONA_API_KEY, UNSPLASH_ACCESS_KEY, and UNSPLASH_SECRET_KEY. Verify these are set:
docker logs viber
Look for error messages about missing environment variables.

Port already in use

If port 3000 is already in use, map to a different port:
docker run --rm -p 8080:3000 \
  -e GEMINI_API_KEY=... \
  viber
Access at http://localhost:8080

Build fails

docker build --no-cache -t viber .

Client-side environment variable not working

Client-side environment variables are compiled during build. Modify the Dockerfile before building:
ENV VITE_ELEVENLABS_AGENT_ID=your_actual_agent_id
RUN rm -rf .output && bun run build
Then rebuild:
docker build -t viber .

Build docs developers (and LLMs) love