Summary Link to heading

The goal of this how-to guide is to provide you with a clear and concise step-by-step process for deploying Hugo on your Cloudron Server, along with other essential software.

Operating System Link to heading

Ubuntu / Debian

Software Link to heading

Cloudron Link to heading

Setting up Cloudron is straightforward by following the excellent official documentation available here.

Surfer Link to heading

I use Cloudron’s Surfer app to host my Hugo site. Surfer is a simple and efficient static file server, which, when combined with Drone CI and Gitea, enables automatic deployment of static files.

Gitea Link to heading

Gitea, a lightweight code hosting solution written in Go, is available on Cloudron. We utilize Gitea to host HUGO-generated files and manage blog posts and pages in markdown (.md) format.

Drone CI Link to heading

Drone, powered by Harness™, is a modern Continuous Integration platform that streamlines build, test, and release workflows with its powerful, cloud-native pipeline engine.

We’ll host Drone on a separate machine (in my case, a Proxmox Docker LXC) to manage workload execution on your Cloudron server.

Drone Runner Link to heading

Drone runners continuously check the server for workloads to execute. The Docker runner, for example, operates within ephemeral Docker containers to execute pipeline steps.

fbartels' Cloudron Solution Link to heading

I highly recommend using Drone CI for Cloudron by fbartels. Consider sponsoring fbartels to show appreciation for his valuable contributions.

This custom Cloudron app enables easy deployment of Drone CI on your Cloudron Server and its runner via Docker on your LXC server.

Cloudron CLI Link to heading

The Cloudron CLI is a command-line tool designed for building and installing custom apps on Cloudron.

Info: Do not install on the Cloudron Server, the Cloudron CLI is intended to be installed on an other device then your Cloudron Server.

Hugo Link to heading

Hugo stands out as one of the most popular open-source static site generators, entirely free to use.

Combined with git, Hugo facilitates easy website development. As soon as you push updates to your Gitea instance, Hugo automatically builds your website.

Step-by-Step Guide Link to heading

Let’s get started with deploying Surfer and Gitea on your Cloudron server. Once complete, we’ll set up the Drone CI solution to automate content deployment to your website via Drone > Gitea > Surfer.

Note: Never perform these steps on your Cloudron Server itself. Utilize any Linux-compatible device, like WSL for Windows, or any other Linux device. Please be aware that Windows support for this setup has not been tested by me; I use WSL as a recommended option.

Preparation Link to heading

Choose a Linux-compatible device for this setup. In my case, I utilize a Docker LXC (Proxmox) from tteck to enjoy a fully dockerized environment available 24/7 when needed.

On the Docker LXC, install the following packages using apt:


Ensure that npm is updated to the latest version to avoid errors with Cloudron CLI:

npm install -g n
n stable

The Cloudron CLI can be installed on Linux using the following command:

sudo npm install -g cloudron

Docker Hub Link to heading

Create yourself an account on Docker Hub. Remember your username as you will need that later in this guide.

Installation Link to heading

Drone CI Link to heading

  1. Go to your desired folder on your Linux machine.

  2. Login to your own Cloudron Instance via Cloudron CLI:

    cloudron login
  3. Clone the repo and cd into it:

    git clone && cd cloudron-drone-app
  4. Do the magic with the following command:

    DOCKER_REPO=your-docker-hub-user make install

    Info: Because you used cloudron login, your Drone custom app will be deployed on your Cloudron server. The URL will be

  5. Create an OAuth at your own Gitea environment. See this for more information.

  6. Back on your Linux machine (with this command, you go into the bash of your Drone instance at Cloudron):

    make exec
  7. Edit the following file:

    nano .env
  8. Fill in your URL, Client ID, and Secret from Gitea.

    DRONE_GITEA_CLIENT_ID=<see step 5>

    The rest is already pre-filled; just don’t touch it.

  9. When you’ve successfully made your edits, you’ll have to restart your Drone application. You can do this by executing:

    cloudron restart

Runner Link to heading

We have to make some edits to the original script to make it work.

  1. nano runner/
    set -x
    random_string() {
            LC_CTYPE=C tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c32
    update_env_file () {
        if ! grep -q "$varname" ./.env; then
            echo "$varname=$varvalue" >> ./.env
            sed -i "/$varname/c $varname=$varvalue" ./.env
    cloudron pull /app/data/.env .env
    . ./.env
    update_env_file DRONE_RPC_SERVER "https://$DRONE_SERVER_HOST"
    update_env_file DRONE_RPC_HOST "$DRONE_SERVER_HOST"
    update_env_file DRONE_RUNNER_CAPACITY "$(nproc)"
    update_env_file DRONE_RUNNER_NAME "$(hostname)"
    docker compose up -d

    The above is a bit different from the original script; I’ve added the following line:

    update_env_file DRONE_RPC_HOST "$DRONE_SERVER_HOST"

    and I’ve replaced docker-compose with docker compose.

  2. Save that; we will return to this later.

Surfer Link to heading

  1. Navigate to your Cloudron app: Surfer (example:
  2. Click on the link ‘Manage your files in your browser'; this will redirect you to the admin panel of Surfer. You can log in using the same credentials you use for your Cloudron environment.
  3. On the top right, click on the three dots to open the menu. From there, click on ‘Access Tokens’. Click on the button ‘Create Access Token’ and save that somewhere in your notes because you’ll need that in the next steps.

Gitea Link to heading

If you haven’t created any repo yet for your Gitea environment, I recommend you to do that now. Once you’ve done that, you can use that repo to host your code from Hugo.

Example: randyjc/example_hugo - example_hugo - Gitea (

Drone CI Link to heading

  1. Go back to your Drone instance and activate the repository that you have just created on your Gitea environment.

    Info: If you don’t see your repo, click on SYNC (top right button).

  2. Once it’s activated, you’ll be presented with the settings page.

  3. Go to Secrets (not under Organization) and click on the button ‘+ NEW SECRET’.

  4. Fill in the following:

    • Name: surftoken
    • Value: <see step 3 under surfnet>
    • Make sure that ‘Allow Pull Requests’ is unchecked.
  5. Click ‘Create’.

Runner Link to heading

  1. Go back to your terminal and run the following command:

    cd runner/ && ./

    Info: When executing the script outside this folder, you’ll get the error that it cannot find any configuration file.

    Output should look like this:

    + cloudron pull /app/data/.env .env
    + . ./.env
    + update_env_file DRONE_RPC_SERVER
    + varname=DRONE_RPC_SERVER
    + varvalue=
    + grep -q DRONE_RPC_SERVER ./.env
    + echo DRONE_RPC_SERVER=
    + update_env_file DRONE_RPC_HOST
    + varname=DRONE_RPC_HOST
    + grep -q DRONE_RPC_HOST ./.env
    + echo
    + nproc
    + update_env_file DRONE_RUNNER_CAPACITY 2
    + varvalue=2
    + grep -q DRONE_RUNNER_CAPACITY ./.env
    + hostname
    + update_env_file DRONE_RUNNER_NAME drone-ci
    + varname=DRONE_RUNNER_NAME
    + varvalue=drone-ci
    + grep -q DRONE_RUNNER_NAME ./.env
    + echo DRONE_RUNNER_NAME=drone-ci
    + docker compose up -d
    [+] Running 1/0
     ✔ Container drone-agent  Running 
  2. If you run docker ps, you can see the container is running:

3c7518132092 drone/drone-runner-docker:1.8 “/bin/drone-runner-d…” 1 minute ago Up 1 minute 3000/tcp drone-agent

Hugo Link to heading

You can run Hugo on any machine you like, as long as you have git and Hugo installed. For simplicity of this guide, I just use the exact same machine where I have the runner running as well.

  1. Go to your terminal where you have Hugo and git available and cd to your desired location for your git repo.

  2. Once there, follow these simple commands:

    hugo new site mywebsitename && cd mywebsitename
    git init
    git remote add origin<user>/<your-git-repo>.git
    git submodule add themes/ananke
    echo theme = '"ananke"' >> config.toml
    hugo new posts/
    hugo -D
  3. You’ll now have to create the config file for your Drone CI instance so that the runner knows what to do with it:

    nano .drone.yml
  4. Paste the following inside that file:

    kind: pipeline
    name: blog_website
      limit: 1
      - name: submodules
        image: alpine/git
          - git submodule update --init --recursive --remote
      - name: build
        image: plugins/hugo
          hugo_version: 0.79.0
          extended: true
          validate: true
      - name: deploy
        image: 'fbartels/cloudron-surfer:5.12.2'
            from_secret: surftoken
          - surfer --version
          - touch public/ # touch folder to avoid problems with timestamps
          - surfer put --token $SURFTOKEN --server ./public/* / 
            - main
              - pull_request

    Save & exit the file.

  5. Follow these commands:

    git add .
    git commit -m "first push to Gitea"
    git push origin main

If everything went well, you have now pushed all the files to your Gitea, and your Drone runner is probably already busy working on deploying it.

Success! Link to heading

Navigate to your domain where you have deployed your Surfer instance, and you’ll see that your Hugo website is now successfully deployed.

Sources Link to heading