Hugo docker + nginx proxy manager docker (solved)

I’ve managed to run hugo on docker thanks to @razon on this other support post.

Now I’ve “managed” to run it behind nginx proxy manager, but I fail to understand how I generate the contents of the public folder using the nextcloud docker.

I run hugo like this:

docker run -p 1313:1313 \
  -v ${PWD}:/src \
  hugomods/hugo:latest \
  hugo server --port=1313 -b="" --appendPort=false --buildDrafts --buildFuture --bind

I run my nginx proxy manager with this compose file (extract):

version: '3'
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
      - '80:80'
      - '81:81'
      - '443:443'
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_DB_MYSQL_USER: myuser
      DB_MYSQL_PASSWORD: "mypassword"
      DB_MYSQL_NAME: "npm"
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
      - /home/user/dockers/web/mywebsite/public:/site

And in the nginx proxy manager GUI interface, for the subdomain, under the Custom Nginx Configuration I put:

location / {
  root /site/;

As shown here.

But, the problem is that running hugo as exposed, the ‘/public’ folder is still empty.

If I try to execute hugo via docker exec -u 33 -it hugo-hugo-1 hugo, I get permission erros:

Start building sites … 
hugo v0.121.1-00b46fed8e47f7bb0a85d7cfc2d9f1356379b740+extended linux/amd64 BuildDate=2023-12-08T08:47:45Z

Total in 19 ms
Error: error building site: failed to acquire a build lock: open /src/.hugo_build.lock: permission denied

I tried with root, just to test:

docker exec -u root -it hugo-hugo-1 /bin/sh

And indeed I could execute hugo command from within and the contents of /public were generated and I could access to the site via https on my subdomain

But the files under /public belong to the root user, which I don’t think is intented, right?

So how show I correctly do it?

I have not looked into your specific case, but I recall running into a similar permissions problem with a Hugo/Docker image.

This is what I ended up with… the user and group id’s solved the problem.

docker run --rm -v .:/project -v $HOME/.cache/hugo_cache:/cache -u $(id -u):$(id -g) --network host veriphor/hugo hugo

I use the image above (sometimes) for local testing/development, and it’s the image I use for GitLab Pages sites. It’s big because it contains all optional dependencies (asciidoctor, pandoc, rst, etc.).


# Base image

# Default shell
SHELL ["/bin/bash", "-c"]

# Working directory
WORKDIR /project

# Intall utilities
RUN apt update && \
    apt upgrade -y && \
    apt install -y --no-install-recommends asciidoctor brotli curl git lsb-release pandoc python3-pip shared-mime-info && \
    apt clean && \
    pip install docutils

# Configure Git
RUN git config --system --add /project && \
    git config --system --add core.quotepath false

# Intall Pagefind (regular and extended)
RUN curl -LJO${VERSION_PAGEFIND}/pagefind-v${VERSION_PAGEFIND}-x86_64-unknown-linux-musl.tar.gz && \
    tar -C /usr/local/bin -xzf pagefind-v${VERSION_PAGEFIND}-x86_64-unknown-linux-musl.tar.gz && \
    rm pagefind-v${VERSION_PAGEFIND}-x86_64-unknown-linux-musl.tar.gz && \
    curl -LJO${VERSION_PAGEFIND}/pagefind_extended-v${VERSION_PAGEFIND}-x86_64-unknown-linux-musl.tar.gz && \
    tar -C /usr/local/bin -xzf pagefind_extended-v${VERSION_PAGEFIND}-x86_64-unknown-linux-musl.tar.gz && \
    rm pagefind_extended-v${VERSION_PAGEFIND}-x86_64-unknown-linux-musl.tar.gz

# Intall Node.js
RUN apt install -y ca-certificates curl gnupg && \
    mkdir -p /etc/apt/keyrings && \
    curl -fsSL | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
    echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg]${VERSION_NODE} nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \
    apt update && \
    apt install nodejs -y && \
    mkdir /.npm && \
    chmod 777 /.npm

# Intall Go
RUN curl -LJO${VERSION_GO}.linux-amd64.tar.gz && \
    tar -C /usr/local -xzf go${VERSION_GO}.linux-amd64.tar.gz && \
    rm go${VERSION_GO}.linux-amd64.tar.gz
ENV PATH="$PATH:/usr/local/go/bin"

# Intall Dart Sass
RUN curl -LJO${VERSION_DART_SASS}/dart-sass-${VERSION_DART_SASS}-linux-x64.tar.gz && \
    tar -xf dart-sass-${VERSION_DART_SASS}-linux-x64.tar.gz && \
    cp -r dart-sass/ /usr/local/bin && \
    rm -rf dart-sass*
ENV PATH="$PATH:/usr/local/bin/dart-sass"

# Install Hugo
RUN curl -LJO${VERSION_HUGO}/hugo_extended_${VERSION_HUGO}_linux-amd64.deb && \
    apt install -y ./hugo_extended_${VERSION_HUGO}_linux-amd64.deb && \
    rm hugo_extended_${VERSION_HUGO}_linux-amd64.deb
ENV HUGO_SECURITY_EXEC_ALLOW="^(asciidoctor|babel|go|npx|pandoc|postcss||sass)$"

# Copy scripts
COPY --chmod=755 /usr/local/bin/info

# Labels
LABEL com.veriphor.hugo.documentation=""
LABEL com.veriphor.hugo.license="Apache-2.0"
LABEL com.veriphor.hugo.source=""
LABEL com.veriphor.hugo.version="${VERSION_HUGO}"
LABEL org.opencontainers.image.authors="Joe Mooring <>"
LABEL org.opencontainers.image.description="Hugo is a static site generator written in Go, optimized for speed and designed for flexibility."
LABEL org.opencontainers.image.documentation=""
LABEL org.opencontainers.image.title="Hugo"
LABEL org.opencontainers.image.url=""
LABEL org.opencontainers.image.vendor="Veriphor LLC"
LABEL org.opencontainers.image.version="${VERSION_HUGO}"

Thanks for the answer, @jmooring!

It gives me:

Error: command error: unknown shorthand flag: 'u' in -u

And I don’t see any reference in man hugo for -u or the word “user” :thinking:.

The -u user:group is a Docker CLI flag, not a Hugo flag.


Now run:

docker run -p 1313:1313 -u $(id -u):$(id -g)\
  -v ${PWD}:/src \
  hugomods/hugo:latest \
  hugo server --port=1313 -b="" --appendPort=false --buildDrafts --buildFuture --bind

But still an empty public folder. And if I get in:

docker exec -u 33 -it crazy_moore /bin/sh

And execute it like:

/src $ hugo
Start building sites … 
hugo v0.121.1-00b46fed8e47f7bb0a85d7cfc2d9f1356379b740+extended linux/amd64 BuildDate=2023-12-08T08:47:45Z

Total in 18 ms
Error: error building site: failed to acquire a build lock: open /src/.hugo_build.lock: permission denied

Still the same error, as you can see.


Okey, since I was executing docker with an specific user/group id, I checked which one actually my user has, which is 1000, and tried with the same one:

docker exec -u 1000 -it crazy_moore /bin/sh

And now public folder content is generated and site can be viewed! Thank you so much!

1 Like

I understand. The command works as expected with the image I referenced when running locally, but your setup is obviously quite different. I was hopeful that the user:group would help resolve your problem, but I guess not.

I’m glad it’s working for you.

1 Like

I was just editing my response!

I just needed to get into that container with the same user id!

id -u
docker exec -u 1000 -it crazy_moore /bin/sh
/src $ hugo
Start building sites … 
hugo v0.121.1-00b46fed8e47f7bb0a85d7cfc2d9f1356379b740+extended linux/amd64 BuildDate=2023-12-08T08:47:45Z

                   | EN  
  Pages            |  7  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     |  0  
  Processed images |  0  
  Aliases          |  1  
  Sitemaps         |  1  
  Cleaned          |  0  

Total in 37 ms

Thanks again!

1 Like

But still an empty public folder.

That’s because hugo server doesn’t output the files to public folder by default (default is memory).
You can either replace hugo server with hugo, or append --renderToDisk flag to hugo server.
I’d recommend using the former if you don’t need the Hugo server.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.