Roots Discourse

Deploy to production server on shared hosting with gulp with FTP

Hi there,

Since most of my clients choose for a cheaper shared hosting solution and therefore I never have SSH access on the production server, I added ftpush to my grunt build command in the previous roots versions: Add ftpush to Grunt Watch?

Now with the new Sage I’m looking for the same setup in Gulp. I installed and configured everything with the suggested Bedrock & Trellis setup before realizing I still need SSH access to actually deploy to remote servers.

I looked at gulp-deploy-ftp:
and vinyl-ftp:

but was wundering if someone already has the same setup for hooking this into the gulp or gulp --production command and if it’s stable enough in practice?

Thanks a lot!

1 Like

Additional question;
What advantages does a Bedrock stacked WP site have if you can’t deploy to a production server with Capistrano due to a lack of SSH access? And if I manually FTP my Bedrock structure over to my production server, which files and folders are actually being used? Are these enough:



Vinyl-ftp seems to work just fine, with the following additions to my gulpfile.js:

// ## Globals
var gutil        = require('gulp-util');
var ftp          = require('vinyl-ftp');

// ### Vinyl FTP
gulp.task('deploy', function() {
  var conn = ftp.create( {
    host:     '',
    user:     'username',
    password: 'password',
    parallel: 10,
    log:      gutil.log
  var globs = [
  // using base = '.' will transfer everything to /public_html correctly
  // turn off buffering in gulp.src for best performance
  return gulp.src( globs, { base: '.', buffer: false } )
    .pipe( conn.newer( '/public_html/web/app/themes/sage' ) ) // only upload newer files
    .pipe( conn.dest( '/public_html/web/app/themes/sage' ) );

// ### Build
// `gulp build` - Run all the build tasks but don't clean up beforehand.
// Generally you should be running `gulp` instead of `gulp build`.
gulp.task('build', function(callback) {
              ['fonts', 'images'],

Since the deploy task also runs on the gulp command, I had to manually exclude the static and maps files in the dist folder to prevent them from being uploaded.

1 Like

Hey Twansparant,

Thanks for your sharings on this! If I want to just run gulp for the local files without a deployment, what task would I run?

As I don’t really want to upload all files each time I run gulp… Or once I’ve done the initial upload will it just upload changed files?



Good question, which I haven’t figured out yet unfortunately…
In previous versions, you just ran gulp build but in Sage just gulp also runs the build task.

It does yes with the following line:

.pipe( conn.newer( '/public_html/web/app/themes/sage' ) )

However the problem is that the entire dist folder gets rebuild on gulp --production which causes the entire folder to get re-uploaded on every build.

Another thing I just bumped into, is that the previous hashed versions of the minified files don’t get deleted from the ftp server. So I tried to add the following line which should delete the remote dist folder entirely before uploading:

.pipe( conn.rmdir( '/domains/' ), cb )

Which does delete the folder, but it gives me a bunch of errors too:

[10:28:57] TypeError: Cannot read property 'on' of undefined
[10:28:57] TypeError: Cannot read property 'on' of undefined
                        cb( err );
TypeError: undefined is not a function

So I placed a callback function within the task:

gulp.task('upload', function(cb) {

But that doesn’t work. I’m not that familiar (yet) with the gulp syntax.
Where should I place the callback and what should go in it?

Could someone give us a hand?

No one appears to have a hand available :frowning:

Solution: Run task only on gulp --production