Dockerfile Templates

When you deploy a repository that doesn't include a Dockerfile, GitBlixt auto-generates one based on the files it detects in the repo (e.g. mix.exs → Elixir, package.json → Node.js). The same templates are listed below so you can copy or download one as a starting point for your project — drop it in as Dockerfile at the root of your repo and customize as needed.

Detection runs in the order shown below. The first match wins, so for example a Ruby repo with gem "rails" in its Gemfile gets the Rails template, not the generic Ruby one.

Elixir / Phoenix

Multi-stage release build on debian-slim.

Detection: mix.exs present

# Auto-generated by GitBlixt for Elixir/Phoenix apps
ARG ELIXIR_VERSION=1.19.5
ARG OTP_VERSION=28.4.1
ARG DEBIAN_VERSION=trixie-20260316-slim

ARG BUILDER_IMAGE="docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="docker.io/debian:trixie-slim"

# --- deps ---
FROM ${BUILDER_IMAGE} AS deps

RUN apt-get update \
  && apt-get install -y --no-install-recommends build-essential git ca-certificates curl \
  && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
  && apt-get install -y --no-install-recommends nodejs \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app

RUN mix local.hex --force && mix local.rebar --force
ENV MIX_ENV="prod"

COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV

RUN mkdir config
COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile

# --- builder ---
FROM deps AS builder
ENV MIX_ENV="prod"

COPY priv priv
COPY lib lib
RUN mix compile

COPY assets assets
RUN if [ -f assets/package.json ]; then npm install --prefix assets --production; fi
RUN mix assets.deploy 2>/dev/null || true

COPY config/runtime.exs config/
RUN mix release --overwrite

# --- runner ---
FROM ${RUNNER_IMAGE} AS final

RUN apt-get update \
  && apt-get install -y --no-install-recommends \
    libstdc++6 openssl libncurses6 locales ca-certificates curl \
  && locale-gen en_US.UTF-8 \
  && rm -rf /var/lib/apt/lists/* \
  && sed -i 's/^tty:x:5:/tty:x:5:nobody/' /etc/group

ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
ENV MIX_ENV="prod"
ENV PHX_SERVER=true
ENV PORT=4000

WORKDIR /app
RUN chown nobody /app
COPY --from=builder --chown=nobody:root /app/_build/prod/rel/ /tmp/rel/
RUN cp -r /tmp/rel/*/* ./ && rm -rf /tmp/rel

USER nobody

EXPOSE ${PORT}

CMD sh -c "if [ -f /app/bin/server ]; then exec /app/bin/server; else exec /app/bin/$(ls /app/bin/ | grep -v '.bat' | head -1) start; fi"

Ruby on Rails

Bundles gems, precompiles assets, runs Puma.

Detection: Gemfile matches /gem\s+['"]rails['"]/

# Auto-generated by GitBlixt for Rails apps
FROM docker.io/ruby:3.3-slim AS base

RUN apt-get update -qq \
  && apt-get install -y --no-install-recommends \
    build-essential git libpq-dev curl ca-certificates nodejs npm \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app

ENV RAILS_ENV=production
ENV BUNDLE_DEPLOYMENT=true
ENV BUNDLE_WITHOUT=development:test

COPY Gemfile Gemfile.lock* ./
RUN bundle install --jobs 4

COPY . .

# If database.yml is missing (e.g. gitignored), generate one that reads DATABASE_URL
RUN if [ ! -f config/database.yml ]; then \
      printf 'production:\n  url: <%%= ENV["DATABASE_URL"] %%>\n' > config/database.yml; \
    fi

RUN if [ -f bin/rails ]; then \
      bundle exec rails assets:precompile 2>/dev/null || true; \
    fi

ENV PORT=4000

EXPOSE ${PORT}

CMD bundle exec puma -b tcp://0.0.0.0:${PORT}

Ruby (Sinatra / Rack)

Generic Ruby app — runs config.ru via rackup or app.rb directly.

Detection: Gemfile present

# Auto-generated by GitBlixt for Ruby apps (Sinatra, Rack, etc.)
FROM docker.io/ruby:3.3-slim

RUN apt-get update -qq \
  && apt-get install -y --no-install-recommends \
    build-essential git libpq-dev curl ca-certificates \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app

ENV BUNDLE_DEPLOYMENT=true
ENV BUNDLE_WITHOUT=development:test

COPY Gemfile Gemfile.lock* ./
RUN bundle install --jobs 4

COPY . .

ENV PORT=4000
EXPOSE ${PORT}

CMD sh -c "if [ -f config.ru ]; then exec bundle exec rackup --host 0.0.0.0 --port ${PORT}; elif [ -f app.rb ]; then exec bundle exec ruby app.rb; else echo 'No config.ru or app.rb found — customize the Dockerfile CMD'; exit 1; fi"

Node.js

Installs dependencies, runs build script if present, starts via npm start.

Detection: package.json present

# Auto-generated by GitBlixt for Node.js apps
FROM docker.io/node:22-slim AS deps

WORKDIR /app

RUN apt-get update \
  && apt-get install -y --no-install-recommends ca-certificates \
  && rm -rf /var/lib/apt/lists/*

COPY package*.json ./
RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi

# --- builder ---
FROM deps AS builder
COPY . .
RUN npm run build --if-present

# --- runner ---
FROM docker.io/node:22-slim AS final

WORKDIR /app

RUN apt-get update \
  && apt-get install -y --no-install-recommends ca-certificates dumb-init \
  && rm -rf /var/lib/apt/lists/*

ENV NODE_ENV=production
ENV PORT=4000

COPY --from=builder /app /app

EXPOSE ${PORT}

CMD ["dumb-init", "npm", "start"]

Python

pip install + gunicorn. Detects Django, Flask-style apps at runtime.

Detection: any of: requirements.txt, pyproject.toml

# Auto-generated by GitBlixt for Python apps
FROM docker.io/python:3.12-slim

WORKDIR /app

RUN apt-get update \
  && apt-get install -y --no-install-recommends \
    build-essential libpq-dev curl ca-certificates \
  && rm -rf /var/lib/apt/lists/*

COPY requirements.txt* pyproject.toml* poetry.lock* ./

RUN if [ -f requirements.txt ]; then \
      pip install --no-cache-dir -r requirements.txt; \
    elif [ -f pyproject.toml ]; then \
      pip install --no-cache-dir .; \
    fi \
 && pip install --no-cache-dir gunicorn

COPY . .

ENV PORT=4000
ENV PYTHONUNBUFFERED=1

EXPOSE ${PORT}

# Auto-detects Django (manage.py), then falls back to wsgi.py / app.py / main.py.
# ASGI (FastAPI, Starlette) users should replace this with a uvicorn invocation.
CMD sh -c '\
if [ -f manage.py ]; then \
  python manage.py migrate --noinput; \
  WSGI_DIR=$(find . -maxdepth 3 -name wsgi.py -not -path "./.*" | head -1 | xargs dirname | sed "s|^\./||"); \
  exec gunicorn --bind 0.0.0.0:$PORT "${WSGI_DIR}.wsgi:application"; \
elif [ -f wsgi.py ]; then exec gunicorn --bind 0.0.0.0:$PORT wsgi:application; \
elif [ -f app.py ]; then exec gunicorn --bind 0.0.0.0:$PORT app:app; \
elif [ -f main.py ]; then exec gunicorn --bind 0.0.0.0:$PORT main:app; \
else echo "No entry point found (manage.py, wsgi.py, app.py, or main.py)"; exit 1; \
fi'

Go

Multi-stage build with static binary on debian-slim.

Detection: go.mod present

# Auto-generated by GitBlixt for Go apps
FROM docker.io/golang:1.23-bookworm AS builder

WORKDIR /app

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

COPY . .

# If a cmd/ directory exists, build the first command found there;
# otherwise build the package at the repo root.
RUN if [ -d cmd ] && [ -n "$(ls -A cmd 2>/dev/null)" ]; then \
      MAIN=$(ls cmd | head -1); \
      CGO_ENABLED=0 GOOS=linux go build -o /app/server ./cmd/$MAIN; \
    else \
      CGO_ENABLED=0 GOOS=linux go build -o /app/server .; \
    fi

# --- runner ---
FROM docker.io/debian:trixie-slim AS final

RUN apt-get update \
  && apt-get install -y --no-install-recommends ca-certificates \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY --from=builder /app/server /app/server

ENV PORT=4000
EXPOSE ${PORT}

CMD ["/app/server"]

Static HTML / CSS

Serves files via nginx with SPA-style fallback to index.html.

Detection: index.html present

# Auto-generated by GitBlixt for static HTML/CSS sites
FROM docker.io/nginx:alpine

COPY . /usr/share/nginx/html

RUN printf 'server {\n  listen 4000;\n  root /usr/share/nginx/html;\n  index index.html;\n  location / { try_files $uri $uri/ /index.html; }\n}\n' \
    > /etc/nginx/conf.d/default.conf

ENV PORT=4000
EXPOSE 4000

CMD ["nginx", "-g", "daemon off;"]

How auto-detection works

On every successful CI pipeline, the deploy worker checks the repository for a Dockerfile, Dockerfile.build, Dockerfile.prod, or Dockerfile.production. If one exists, it's used as-is. If none exist, the templates above are tried in order, and the first whose detection rule matches the repo is used to build the image.

You can force template generation (ignoring an existing Dockerfile) by setting an environment's dockerfile_mode to auto.