DEV Community

Cover image for Publish static website with Travis to existing FTP server
Josef Biehler
Josef Biehler

Posted on • Updated on

Publish static website with Travis to existing FTP server

Note: You can checkout the runnable example at the this blog post's repo.

IMPORTANT: Unfortunately travis does not support FTP. See this article for a explanation:

In the last article I showed you how you can create a static website using 11ty. Now we want to publish the output somewhere. As I am paying for webspace it makes sense, that I deploy the page there by using a ftp client. Of course you can choose any webhoster for this.

FTP upload

I choose ftp-client for this task as it is very easy to use.

All HTML resides in /dist so we just need to take all of the directory and upload it to the root directory.

// project/ftp.js

const FtpClient = require('ftp-client');

async function upload() {
    const config = {
        host: process.env.FTP_SERVER,
        user: process.env.FTP_USER,
        password: process.env.FTP_PWD,
        port: 21,
        secure: true

    const options = {
        logging: 'basic'

    const client = new FtpClient(config, options);

    client.connect(function () {
        client.upload(['dist/**'], '/', {
            overwrite: 'older'
        }, function (result) {


Please note the usage of environment variables here. Later on I show you how to use them in travis.


The page should be built after each commit. As my site is open source I can use travis for free.

language: node_js

    - ~/.npm

  - '11'

  - npm run 11ty
  - npm run upload

It is a very simple config.

  • you define the language (node_js)
  • cache .npm to speed up your build. Otherwise travis will download all dependencies in every build
  • define the node version
  • list all npm scripts that should be executed.

I do not want to write about the usage of travis here. contains a lot of posts about it. If you have question, leave a comment 👍

Run the build every day:

You should configure a cron job to ensure that your build runs at least once per day and can fetch the latest tweets and posts.

This must be done in the WebUI. First in your build go to the settings:

Here you can create cron jobs the way you want. My build should run every day:
cron job

Set environment variables:

The code of my page is public so I don't want to commit my ftp user data. For this and similar tasks you can configure environment variables. Those are not visible to anyone.

env vars

Of course you should not display the values in your build log because this is public to everyone.


This was a quick introduction into travis. Of course you can upload your files every time manually to the ftp server. But this is annoying and consumes time. So I suggest you to familiarize yourself with one of the free CI server. It is definitely worth a look!

What is next?

The next time we will have a look at creating a design with 11ty. It will be very basic and I only want to show you some 11ty basics.
Also we must think about how we can fetch tweets.

Found a typo?

As I am not a native English speaker, it is very likely that you will find an error. In this case, feel free to create a pull request here: . Also please open a PR for all other kind of errors.

Do not worry about merge conflicts. I will resolve them on my own.

Top comments (8)

chfrom77 profile image
Christian H From

Hi Josef - thanks for the nice tutorials!
A quick question though: When I do a build, 11ty generates each file as index.html and puts each output file into its own folder. Running a local server with 11ty just works of course, but uploading the _site folder to my hosting account breaks all links - which makes sense, considering everything is inside its own folder and named index.html. I cannot find anywhere how to simply ftp a build onto a server. Am I missing something in the config?
Sorry to ask - Eleventy seems nice, but there is still not too much info about it out there.

gabbersepp profile image
Josef Biehler • Edited

Hey Christian,

if you have a file structure like this:

and run 11ty, you get following files:


So you need an (or any other supported format) in the root of your /views directory.

Let me know if you need further assistance :)

chfrom77 profile image
Christian H From

If by /views you mean root, then I have an index.njk file. Eleventy turns that (and all other md files) into index.html. I guess I just don't get how to get from that, to something which will actually work when I deploy it. I am used to files called about.html, contact.html, etc, but I guess the 11ty server has a way of making sense of similarly named files with different paths? I actually have a feeling this can be fixed with permalinks somehow, but again, this is not explained too well at Hmm... but thanks for your answer!

Thread Thread
gabbersepp profile image
Josef Biehler

I am not sure if I understand what you mean :-)

Please have a look at this example:

Feel free to make a pull request to show me an example of your code :)

Thread Thread
chfrom77 profile image
Christian H From

It's kind of hard to explain :-)
I see your links look like this: "about/index.html"
While mine look like this: "/About" or "/posts/2020/blog-post-3/"
My links work locally, but not on my remote server. It makes sense to me now, that there should be a html file at the end of that string, but I'm new to this SSG-thing, so everything looks strange to me ;-). But did you set those link urls manually? That would seem inefficient...

Thread Thread
gabbersepp profile image
Josef Biehler • Edited

In my case "/about" would also work, because the HTTP server usually knows that it must serve a file called "".

But if you using "/About" but your file is named "about.njk" then it will work locally on your windows (if you have one) but not on your remote server (that probably is a linux server) because of the casing of "A".

e.g. works but works, too. The server delivers the same page for both links.

The links in this simple example are manually added. But this does not matter I think.

"/posts/2020/blog-post-3/" should also work if there is an index.html file located within that folder. Maybe the setting of your remote http server is wrong and it does not know anymore what file should be served?

Thread Thread
chfrom77 profile image
Christian H From

Hmm, yes, that makes sense. I read up on links: and I'm starting to understand the 11ty file/folder structure. But perhaps my server doesn't get it ;-)

Thread Thread
chfrom77 profile image
Christian H From • Edited

Figured it out! I started an issue (closed now - yay) about the whole thing, and finally was able to wrap my head around what I was doing right and wrong. Thanks a lot for your time as well - you got me on the right path to the answer(s)! Here's the issue, btw: