🚀 Containerizing My Go Telegram Bot: Lessons, Wins & Gotchas

Hey folks! 👋
Recently, I took on the task of containerizing my Telegram bot project — built with Go — and thought I’d share how that adventure went. The bot, which I lovingly call socdownbro
, is a Telegram bot that fetches and downloads social media videos. It's based on Telegram Bot API Framework and uses yt-dlp
, ffmpeg
, and a few custom tweaks. While the Go codebase was solid, getting it into a clean, reusable Docker image took a bit of finesse.
So here’s a walk-through of my experience — including my Dockerfile
, docker-compose.yaml
, and a few nuggets of wisdom I picked up along the way.
🏗️ Step 1: Building the Dockerfile
Here’s the full Dockerfile I ended up with:
# Use a minimal image to run the application
FROM golang:1.24-alpine AS builder
# CGO_ENABLED is needed to build go-sqlite3
RUN apk add --no-cache --update go gcc g++
# Set working directory
WORKDIR /usr/src/app
ENV CGO_ENABLED=1
# Cache deps
COPY go.mod go.sum ./
RUN go mod download
RUN go mod verify
# Copy source
COPY . .
# Run tests (because CI/CD is in my blood 💉)
RUN go test -v ./...
# Build binary
RUN go build -v -o socdownbro .
# Final minimal image
FROM alpine:latest
# Add ffmpeg and yt-dlp for video processing
RUN apk --no-cache add ffmpeg yt-dlp
WORKDIR /bot
COPY --from=builder /usr/src/app/socdownbro .
COPY --from=builder /usr/src/app/config.json .
COPY res ./res/
CMD ["/bot/socdownbro"]
💡 Why Multi-Stage?
Multi-stage builds keep my image lean. I compile everything in the builder stage (with all the heavy Go toolchain), and then ship only what I need — the binary, config, and resources — into the final image. Clean and tiny. Alpine helps too!
🧩 Step 2: Orchestrating with Docker Compose
To keep things maintainable and reproducible, I used Docker Compose to wire up everything, including the PostgreSQL DB and Telegram Bot API server.
Here’s the docker-compose.yaml
:
services:
socialdownbro-bot:
container_name: socialdownbro-bot
build:
context: .
dockerfile: Dockerfile
environment:
- DB_DATABASE=${DB_NAME}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- DB_HOST=${DB_HOST}
- DB_PORT=${DB_PORT}
- DB_SCHEMA=${DB_SCHEMA}
volumes:
- videos:/bot/videos:rw
depends_on:
- botanium-db
- telegram-bot-api
restart: unless-stopped
telegram-bot-api:
image: aiogram/telegram-bot-api:latest
environment:
TELEGRAM_API_ID: "${TELEGRAM_API_ID}"
TELEGRAM_API_HASH: "${TELEGRAM_API_HASH}"
volumes:
- telegram-bot-api-data:/var/lib/telegram-bot-api
ports:
- "8081:8081"
restart: unless-stopped
botanium-db:
image: postgres:17-alpine
environment:
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
ports:
- "127.0.0.1:5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
telegram-bot-api-data:
pgdata:
videos:
🔍 Highlights
depends_on
: Ensures the DB and Telegram API start before the bot.Volumes:
videos
is used to persist downloads.pgdata
holds our database files.telegram-bot-api-data
keeps the Telegram API data stable between restarts.
🧠 What I Learned
✅ Wins
Go binaries are Docker’s best friend: A statically compiled Go app is incredibly easy to containerize. No JVMs, no interpreters. Just copy and run.
Multi-stage builds are game changers. Clean separation of concerns, faster rebuilds, smaller images.
Local testing was easy: Thanks to Compose, I could bring up the whole environment with a single command. Great for rapid iteration.
⚠️ Gotchas
SQLite in Docker: I had to enable
CGO_ENABLED=1
and include build tools because of thego-sqlite3
dependency. Alpine doesn’t come with glibc, so this needed some tweaking.yt-dlp & ffmpeg in Alpine: I initially tried to use Alpine’s versions, but sometimes they lag behind. If I hit any weird bugs, I might switch to a Debian-based image later on.
Telegram Bot API service: Running your own instance gives more control, but be ready to monitor it — especially for TLS and auth issues if you go public.
🤓 Final Thoughts
Containerizing my Telegram bot was super satisfying. Now I can deploy anywhere — my dev machine, a VPS, or even Kubernetes down the road. Plus, I get consistent, predictable environments. No more "it works on my machine" moments.
If you’re building bots with Go (or really anything else), I highly recommend giving Docker a shot. It’s not as scary as it looks, and once you get the hang of it, it’s like having a superpower. 🦸♂️
Let me know if you’d like me to open source socdownbro
or write a follow-up on deploying it to the cloud. Till then — happy coding! 💻✨
Subscribe to my newsletter
Read articles from Amurru Zerouk directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
