Guides
Your own Dockerfile — Go, Rust, Java and anything else
For languages Meghly does not build by itself (Go, Rust, Java, Elixir …), or when you need a build of your own, run the app with your own Dockerfile.
For ASP.NET Core, Node.js, Python, PHP and static sites Meghly makes the build itself — no Dockerfile needed. For anything else (Go, Rust, Java/Spring, Elixir, Deno, Bun …), bring your own Dockerfile.
Telling the app to use the Dockerfile
A Dockerfile in the repository is not used by itself — the app's kind has to say so:
- Apps → New app → a Git repository or a zip.
- In What is it? choose Dockerfile.
- If the Dockerfile is not at the repository's root (and there is more than one), under Advanced:
- Dockerfile path — from the repository's root, such as
src/Shop.Api/Dockerfile. - Build context — the folder the build sees; empty means the repository's root.
- Dockerfile path — from the repository's root, such as
To change them later, the app's General page has the same two fields.
Unless the kind is Dockerfile, Meghly tries to recognise the app its own way. When it recognises nothing but finds a Dockerfile, Detect tells you: set the app's kind to Dockerfile.
The rules
| Rule | Why, and what to do |
|---|---|
| Port | Taken from the final stage's EXPOSE. With no EXPOSE, or a port below 1024, the app must listen on PORT (8080). |
| Not root | The app always runs as an ordinary (non-root) user, so it cannot listen on 80 or 443. |
| Read-only | While running, it can write only to /tmp and the app's volumes. |
| Build context | .git, node_modules, bin, obj and .env files never reach the build — install dependencies inside the Dockerfile and set secrets on the app. Your .dockerignore is honoured too. |
| Time | A build may take up to 15 minutes. |
Health checks, release commands, workers, cron, volumes, domains and databases all work as for any other app.
Example: Go
FROM golang:1.25-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/server
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
EXPOSE 8080
ENTRYPOINT ["/app"]port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.ListenAndServe(":"+port, mux)Example: Java (Spring Boot)
FROM eclipse-temurin:21-jdk AS build
WORKDIR /src
COPY . .
RUN ./mvnw -q -DskipTests package
FROM eclipse-temurin:21-jre
COPY --from=build /src/target/*.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]To make Spring Boot read PORT:
server.port=${PORT:8080}Example: Rust
FROM rust:1-slim AS build
WORKDIR /src
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
COPY --from=build /src/target/release/server /usr/local/bin/server
EXPOSE 8080
CMD ["server"]Databases and variables
A linked database brings the same variables to a Dockerfile app: DATABASE_URL, DB_HOST, DB_PORT … (Databases). Read them at run time, not during the build.
When something goes wrong
| What you see | Cause and fix |
|---|---|
| Detect: "set the App's runtime to Dockerfile" | Set the kind to Dockerfile in What is it? / General. |
| Detect: "EXPOSEs port 80, which only root may open" | Make the app listen on PORT (8080) and EXPOSE 8080. |
COPY failed: … not found | Check the Build context, and that the file is not under .git / node_modules or an .env. |
read-only file system | Write to /tmp or a volume. |