Velld LogoVelld

Installation

Get started with Velld in minutes

Installation

Velld is designed to be simple to install and run. Choose the installation method that works best for you.

Prerequisites

Before you begin, ensure you have:

  • Docker and Docker Compose installed
  • At least 512MB RAM and 1GB disk space
  • A database you want to backup (PostgreSQL, MySQL, MongoDB, or Redis)

Velld only installs the database clients you need. This keeps the Docker image lightweight and secure.

Quick Start

Fastest way - Pull and run pre-built images directly (no git clone needed):

# Pull images
docker pull ghcr.io/dendianugerah/velld/api:latest
docker pull ghcr.io/dendianugerah/velld/web:latest

# Create .env file
cat > .env << EOF
NEXT_PUBLIC_API_URL=http://localhost:8080
JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
ADMIN_USERNAME_CREDENTIAL=admin
ADMIN_PASSWORD_CREDENTIAL=changeme
ALLOW_REGISTER=true
EOF

# Run API
docker run -d \
  --name velld-api \
  -p 8080:8080 \
  --env-file .env \
  -v velld-data:/app/data \
  -v velld-backups:/app/backups \
  ghcr.io/dendianugerah/velld/api:latest

# Run Web
docker run -d \
  --name velld-web \
  -p 3000:3000 \
  -e NEXT_PUBLIC_API_URL=http://localhost:8080 \
  -e ALLOW_REGISTER=true \
  ghcr.io/dendianugerah/velld/web:latest

Important: The data directory has changed from /app/internal/database to /app/data.

Open http://localhost:3000 in your browser.


Using Docker Compose

If you prefer docker-compose:

git clone https://github.com/dendianugerah/velld.git
cd velld
cp .env.example .env
docker compose -f docker-compose.prebuilt.yml up -d

Build from Source

If you want to build the images yourself:

git clone https://github.com/dendianugerah/velld.git
cd velld
cp .env.example .env
docker compose up -d

Database-Specific Installation

Choose only the database client you need to keep your installation lightweight:

PostgreSQL Only

1. Create a custom Dockerfile

Create apps/api/Dockerfile.postgres:

FROM golang:1.24-alpine AS builder

WORKDIR /app

RUN apk add --no-cache gcc musl-dev

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=1 GOOS=linux go build -o main cmd/api-server/main.go

FROM alpine:latest

# Install only PostgreSQL client
RUN apk add --no-cache \
    sqlite-libs \
    postgresql-client

WORKDIR /app

COPY --from=builder /app/main .
COPY --from=builder /app/internal/database ./internal/database

EXPOSE 8080

CMD ["./main"]

2. Update docker-compose.yml

services:
  api:
    build:
      context: ./apps/api
      dockerfile: Dockerfile.postgres  # Use PostgreSQL-only Dockerfile
    ports:
      - "8080:8080"
    env_file:
      - .env
    volumes:
      - api_data:/app/data
      - backup_data:/app/backups
    restart: unless-stopped

  web:
    build:
      context: ./apps/web
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
      ALLOW_REGISTER: ${ALLOW_REGISTER}
    depends_on:
      - api
    restart: unless-stopped

volumes:
  api_data:
  backup_data:

3. Start the services

docker compose up -d

Your PostgreSQL-only installation is now running! Image size: ~50MB lighter.

MySQL Only

1. Create a custom Dockerfile

Create apps/api/Dockerfile.mysql:

FROM golang:1.24-alpine AS builder

WORKDIR /app

RUN apk add --no-cache gcc musl-dev

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=1 GOOS=linux go build -o main cmd/api-server/main.go

FROM alpine:latest

# Install only MySQL client
RUN apk add --no-cache \
    sqlite-libs \
    mysql-client

WORKDIR /app

COPY --from=builder /app/main .
COPY --from=builder /app/internal/database ./internal/database

EXPOSE 8080

CMD ["./main"]

2. Update docker-compose.yml

services:
  api:
    build:
      context: ./apps/api
      dockerfile: Dockerfile.mysql  # Use MySQL-only Dockerfile
    ports:
      - "8080:8080"
    env_file:
      - .env
    volumes:
      - api_data:/app/data
      - backup_data:/app/backups
    restart: unless-stopped

  web:
    build:
      context: ./apps/web
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
      ALLOW_REGISTER: ${ALLOW_REGISTER}
    depends_on:
      - api
    restart: unless-stopped

volumes:
  api_data:
  backup_data:

3. Start the services

docker compose up -d

Your MySQL-only installation is now running! Image size: ~45MB lighter.

MongoDB Only

1. Create a custom Dockerfile

Create apps/api/Dockerfile.mongo:

FROM golang:1.24-alpine AS builder

WORKDIR /app

RUN apk add --no-cache gcc musl-dev

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=1 GOOS=linux go build -o main cmd/api-server/main.go

FROM alpine:latest

# Install only MongoDB tools
RUN apk add --no-cache \
    sqlite-libs \
    mongodb-tools

WORKDIR /app

COPY --from=builder /app/main .
COPY --from=builder /app/internal/database ./internal/database

EXPOSE 8080

CMD ["./main"]

2. Update docker-compose.yml

services:
  api:
    build:
      context: ./apps/api
      dockerfile: Dockerfile.mongo  # Use MongoDB-only Dockerfile
    ports:
      - "8080:8080"
    env_file:
      - .env
    volumes:
      - api_data:/app/data
      - backup_data:/app/backups
    restart: unless-stopped

  web:
    build:
      context: ./apps/web
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
      ALLOW_REGISTER: ${ALLOW_REGISTER}
    depends_on:
      - api
    restart: unless-stopped

volumes:
  api_data:
  backup_data:

3. Start the services

docker compose up -d

Your MongoDB-only installation is now running! Image size: ~60MB lighter.


Environment Configuration

Create a .env file in the project root:

cp .env.example .env

Required Variables

VariableDescriptionExample
NEXT_PUBLIC_API_URLAPI server URL (must be accessible from browser)http://localhost:8080
JWT_SECRETJWT signing key - generate with openssl rand -hex 3264 hex characters
ENCRYPTION_KEYDatabase credential encryption key - generate with openssl rand -hex 3264 hex characters

Production: Always set JWT_SECRET and ENCRYPTION_KEY manually. While they auto-generate if missing, changing keys will log out users and break database connections.

# Generate secure keys
openssl rand -hex 32  # Run twice, once for each

Authentication

VariableDescriptionDefault
ALLOW_REGISTEREnable public registrationtrue
ADMIN_USERNAME_CREDENTIALAdmin username (required if ALLOW_REGISTER=false)-
ADMIN_PASSWORD_CREDENTIALAdmin password (required if ALLOW_REGISTER=false)-

Optional: Email Notifications

Configure SMTP to get notified when backups fail. You can configure these either:

  • Via UI: Go to Settings → Notifications (recommended for most users)
  • Via Environment Variables: Set below variables (useful for Docker/Kubernetes deployments)

When configured via environment variables, these settings become read-only in the UI and cannot be changed from the web interface.

VariableDescriptionDefault
SMTP_HOSTSMTP server hostname-
SMTP_PORTSMTP port587
SMTP_USERSMTP username/email-
SMTP_PASSWORDSMTP password (use App Password for Gmail)-
SMTP_FROMFrom address-

Advanced

VariableDescriptionDefault
DB_PATHPath to Velld's SQLite database/app/data/velld.db
PORTAPI server port8080

Data Persistence: Ensure /app/data is mounted as a volume to persist your database.


Verify Installation

Once the services are running, verify everything works:

  1. Check service status

    docker compose ps
  2. View logs

    docker compose logs -f
  3. Access the web interface

    Open http://localhost:3000 in your browser.

  4. Create your account

    Sign up with your email and start managing backups!


Updating Velld

To update to the latest version:

# Pull the latest changes
git pull origin main

# Rebuild and restart
docker compose down
docker compose up -d --build

Troubleshooting

Services won't start

# Check logs for errors
docker compose logs api
docker compose logs web

# Ensure ports 3000 and 8080 are available
lsof -i :3000
lsof -i :8080

Database connection fails

  • Ensure your database is accessible from the Docker container
  • Use host.docker.internal instead of localhost to connect to databases on your host machine
  • Check firewall rules

Backup fails

  • Verify the database client is installed (check which Dockerfile you're using)
  • Test connection credentials manually
  • Check backup directory permissions