Simple setup for deploying a Vue or React frontend to CPanel-based hosting

So I have several little tools, or apps that I create for convenience and most of them tend to be Single Page applications written with either Vue or React. Sometimes I will make a backend for them and others don't require it. Either way, I sometimes decide to host the front end on a CPanel-based hosting and the back end on a VPS or cloud service somewhere else. As a result, I often have to find a way of "deploying" these applications to CPanel which means uploading the built files via FTP. I have several toy projects and so it became boring to have to upload files via some FTP client, so in this article, I will document one way I have found to ease the drudgery.

It relies on NodeJS, which is typically okay for my project since am most likely using something like Vue or React with Node/npm build system anyways. We only need one extra devDependency: ftpdeploy

$ npm install --save-dev ftp-deploy

Once we have that installed, we can now add the config file for it in ftpdeploy.js which can be setup like below, obviously you would change according to your site details.

import FtpDeploy from "ftp-deploy";
import { cwd } from 'node:process';
import { join } from 'node:path';
const ftpDeploy = new FtpDeploy();

const config = {
    user: "mycpaneluser",
    // Password optional, prompted if none given
    password: null,
    host: "",
    port: 21,
    localRoot: join(cwd(), "./dist"),
    remoteRoot: "/",
    // include: ["*", "**/*"],      // this would upload everything except dot files
    include: ["*", "dist/*", ".*"],
    // e.g. exclude sourcemaps, and ALL files in node_modules (including dot files)
    exclude: [
        // "dist/**/*.map",
    // delete ALL existing files at destination before uploading, if true
    deleteRemote: false,
    // Passive mode is forced (EPSV command is not sent)
    forcePasv: true,
    // use sftp or ftp
    sftp: false,

    .then((res) => console.log("finished:", res))
    .catch((err) => console.log(err));

This script can then be run using NodeJS via node ftpdeploy.jsOr you can add that to your package.json under scripts, something like:

  "scripts": {
    "deploy": "npm run build && node ftpdeploy.js"

Which makes deploying or pushing updates as simple as

$ npm run deploy

That's it, I guess ideally, one should have a nice CI/CD process and better tooling for deploying real-world projects but this setup serves me well for some small toy projects, especially on utilizing my CPanel hosting plan.


  • I recommend trying GitHub actions for a CI/CD process that can deploy sites when you push a tag/release.

  • My friend, Walter, reminded me that we had agreed to atleast publish one post - this post probably wasn't going to get published if it wasn't for his reminder. Checkout his blog