Dockerfile Linter — Hadolint-Style Rules in Browser
Skip to main content

Dockerfile Linter

Lint Dockerfiles against ~25 hadolint-style rules. Catches the highest-value mistakes — floating tags, missing USER, apt cache leaks, shell-form CMDs.

Errors

1

Warnings

12

Info

3

  • warningDL3007line 1

    Avoid :latest tag — pin a specific version

    Hint: Use a digest or specific tag for reproducible builds

  • warningDL4000line 2

    MAINTAINER is deprecated — use LABEL maintainer="..."

  • warningDL3000line 4

    Use absolute WORKDIR path

  • warningDL3020line 5

    Use COPY instead of ADD for files and folders

    Hint: ADD has implicit features (URL fetch, archive extract) that surprise readers

  • warningDL3015line 7

    apt-get install: add --no-install-recommends to keep image small

  • warningDL3009line 7

    Clean up apt-get caches in the same RUN: rm -rf /var/lib/apt/lists/*

  • infoDL3008line 7

    Pin versions in apt-get install (pkg=version)

  • warningDL3014line 7

    Add -y to apt-get install to avoid interactive prompts

  • warningDL3015line 9

    apt-get install: add --no-install-recommends to keep image small

  • warningDL3009line 9

    Clean up apt-get caches in the same RUN: rm -rf /var/lib/apt/lists/*

  • infoDL3008line 9

    Pin versions in apt-get install (pkg=version)

  • errorDL3004line 9

    Do not use sudo — it leads to unpredictable behavior

  • warningDL3011line 11

    EXPOSE port "99999" is out of range (1..65535)

  • warningDL3025line 13

    CMD should use the JSON exec form ["cmd", "arg"] not shell form

  • warningDL3002line 1

    No USER set — image runs as root

    Hint: Add a USER instruction with a non-root user before CMD/ENTRYPOINT

  • infoDL3009line 9

    Multiple RUN apt-get lines — combine into one to reduce layers (2 found)

About Dockerfile Linter

Lint Dockerfiles against ~25 hadolint-style rules covering the highest-value problems: floating tags, missing USER, ADD vs COPY, apt-get cache leaks, pip/npm version pinning, shell-form CMD/ENTRYPOINT, sudo usage, non-absolute WORKDIR, deprecated MAINTAINER, and out-of-range EXPOSE ports. All analysis runs in your browser.

Rule categories

Security

Missing USER (runs as root), sudo usage, :latest tags, ADD with URLs.

Image size

apt-get cache not cleaned, --no-install-recommends missing, pip --no-cache-dir missing, multiple apt-get RUN layers.

Correctness

Shell-form CMD/ENTRYPOINT, non-absolute WORKDIR, cd in RUN, out-of-range EXPOSE.

Maintenance

Deprecated MAINTAINER, unpinned apt/pip/npm versions.

Pipeline

Frequently asked

Why should I avoid the :latest tag?
The :latest tag is mutable — it points to a different image every time the upstream maintainer pushes a new build. Using :latest means your image can change between builds without any change to your Dockerfile, breaking reproducibility. Pin to a specific version tag (e.g. nginx:1.27.0) or a digest (e.g. nginx@sha256:...) for reproducible builds.
Why should I add a USER instruction?
By default, Docker containers run as root. If an attacker exploits a vulnerability in your application, they have root access inside the container. Adding a non-root USER reduces the blast radius. Create a dedicated user in your Dockerfile: RUN addgroup -S app && adduser -S app -G app, then USER app.
Why use COPY instead of ADD?
ADD has two implicit behaviours that surprise readers: it can fetch URLs (downloading arbitrary content at build time) and it automatically extracts tar archives. COPY does exactly one thing: copy files from the build context. Use COPY for files and directories; use ADD only when you specifically need the archive extraction feature.
Why should I clean apt-get caches in the same RUN?
Docker layers are immutable. If you run apt-get install in one RUN and rm -rf /var/lib/apt/lists/* in a separate RUN, the cache files are still present in the first layer and contribute to the final image size. Combining them in a single RUN ensures the cache is never committed to any layer.
What is the exec form vs shell form for CMD and ENTRYPOINT?
Shell form (CMD echo hello) runs the command via /bin/sh -c, which means signals like SIGTERM are sent to the shell, not your process. This causes graceful shutdown to fail. Exec form (CMD ["echo", "hello"]) runs the command directly as PID 1, so signals are delivered correctly. Always use exec form for CMD and ENTRYPOINT.