Changing FTP

The other day I had issues with my FTP server. The ftp action that I was using didn’t catch onto the error where the server was unable to establish a separate channel for transferring the directory information. I decided to change the FTP Action from ftp-action to FTP-Deploy-Action.

Libraryftp-actionFTP-Deploy-Action
Versionreleases/v2v4.3.5
AuthorsebastianpoppSamKirkland
Full Versionsebastianpopp/ftp-action@releases/v2SamKirkland/FTP-Deploy-Action@v4.3.5
SFTPYesYes
Delete all option before uploadYesYes
Dry RunNoYes
Exclude GlobNoYes
Timeout OptionNoYes
StateNoYes
Issueslocal .env file causes issues
Hangs on server errors
Fails without .ftp-deploy-sync-state.json

The action was a little difficult to setup at first. It turns out that you must add a .ftp-deploy-sync-state.json file before it will upload files. This allows it to hash all of the files and determine what has changed. Rather than uploading everything, it only uploads the changed files based on the current file state. This is great when using the composer dependency manager for php as the vendor folder doesn’t change unless you are adding or removing a package. Unfortunately, the documentation isn’t clear that this is required. Here is my YAML in how to use it:

      - name: Prepare FTP
        run: touch src/.ftp-deploy-sync-state.json

      - name: Deploy via FTP
        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
        with:
          server: ${{ vars.DEV_FTP_HOST }}
          username: ${{ secrets.DEV_FTP_USER }}
          password: ${{ secrets.DEV_FTP_PASSWORD }}
          local-dir: 'src/'
          timeout: 2000

You’ll notice that all I am doing is creating a file if it doesn’t exist. It doesn’t have any content.

The FTP state file is just a JSON file listing folders, file names and hashes

{
    "description": "DO NOT DELETE THIS FILE. This file is used to keep track of which files have been synced in the most recent deployment. If you delete this file a resync will need to be done (which can take a while) - read more: https://github.com/SamKirkland/FTP-Deploy-Action",
    "version": "1.0.0",
    "generatedTime": 1717356129387,
    "data": [
        {
            "type": "file",
            "name": ".ftp-deploy-sync-state.json",
            "size": 0,
            "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        },
        {
            "type": "file",
            "name": ".htaccess",
            "size": 1351,
            "hash": "af335f19862bccf6b8d76beb03ffdeb6e29b109de0872d0e246af2c2f6708e0c"
        },
        {
            "type": "folder",
            "name": "common"
        }
}

The other hiccup was that it didn’t recognize src as a folder until I added a trailing slash. Small potatoes.

One thing I love about it is the timeout. Given that I want to fail fast, I prefer low timeouts as anything longer often indicates a problem and just eats up minutes of limited build time I have available.

I had to increase my job timeout to 3 minutes given how long it takes to upload everything (5 MB) during the first run without a state synchronization file on the server. The fact that the FTP action has its own timeout in milliseconds gives me much comfort that things are not going to get hung up for too long if a problem arises.

Another thing I did was to block access to

  • Any file beginning with a dot
  • Vendors folder
  • Non-php extensions

Since the vendors folder is created by composer during the build, I had to add a step to create an .htaccess file during the build before the files are uploaded via FTP.

      - name: Block HTTP access to vendor
        run: |
          touch src/vendor/.htaccess
          echo "Deny from all" >> src/vendor/.htaccess
HTTP Status Code 403
Forbidden

As for all other files, I was able to modify the root .htaccess file under source control.

# Prevent accessing any file beginning wit a dot
<FilesMatch "^\.">
  Order allow,deny
  Deny from all
</FilesMatch>

# Block direct access to files that do not have a .php extension
<FilesMatch "\.(?!php)[a-z0-9]+$">
    Require all denied
</FilesMatch>

If I need to add files like robots.txt later, I’ll have to update the file accordingly. The API server generally doesn’t have anything worthy for a search engine to index as most endpoints require posted content resulting in an error.

{
  "error":"Method not allowed."
}

FTP-Deploy-Action is much more verbose. The original action seemed to be a quick-and-dirty method of simply allowing you to deploy via FTP. This other version seems to be focused on build servers optimizing for speed and verbosity. The logs let you know when the last deployment occurred, the number of files, what is new, what is being replaced, and what is being ignored.

----------------------------------------------------------------
🚀 Thanks for using ftp-deploy. Let's deploy some stuff!   
----------------------------------------------------------------
If you found this project helpful, please support it
by giving it a ⭐ on Github --> https://github.com/SamKirkland/FTP-Deploy-Action
or add a badge 🏷️ to your projects readme --> https://github.com/SamKirkland/FTP-Deploy-Action#badge
----------------------------------------------------------------
Last published on 📅 Sunday, June 2, 2024 at 7:12 PM
----------------------------------------------------------------
Local Files:	1,391
Server Files:	1,390
----------------------------------------------------------------
Calculating differences between client & server
----------------------------------------------------------------
📄 Upload: vendor/.htaccess
🔁 File replace: .htaccess
🔁 File replace: push/.htaccess
🔁 File replace: vendor/composer/autoload_psr4.php
🔁 File replace: vendor/composer/autoload_static.php
⚖️  File content is the same, doing nothing: .ftp-deploy-sync-state.json
⚖️  File content is the same, doing nothing: common/base64url.php

...

replacing ".htaccess"
replacing "push/.htaccess"
replacing "vendor/composer/autoload_psr4.php"
replacing "vendor/composer/autoload_static.php"
----------------------------------------------------------------
🎉 Sync complete. Saving current server state to "./.ftp-deploy-sync-state.json"
----------------------------------------------------------------
Time spent hashing: 426 milliseconds
Time spent connecting to server: 1 second
Time spent deploying: 2.1 seconds (5.5 kB/second)
  - changing dirs: 152 milliseconds
  - logging: 36 milliseconds
----------------------------------------------------------------
Total time: 4.4 seconds
----------------------------------------------------------------

Discover more from Lewis Moten

Subscribe now to keep reading and get access to the full archive.

Continue reading