DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

SSL Certificate renewal for a VSFTP server on Linux

— ny_wk

SSL Certificate renewal for a VSFTP server on Linux

Renewing the vsftpd SSL certificate on a Linux FTP server means generating a fresh private key and CSR, getting a new signed certificate from your CA, pointing vsftpd.conf at the new files, and restarting the service. Done in the right order with a backup first, the whole job takes minutes and causes zero downtime for explicit FTPS clients.

This guide walks through a real-world SSL certificate renewal for a vsftpd server, fixes the common mistakes that break the daemon on restart, and shows you how to verify the new certificate is actually being served. It applies to RHEL/CentOS, Rocky/Alma, and Debian/Ubuntu hosts running vsftpd with ssl_enable=YES.

The problem: an expiring vsftpd certificate

vsftpd uses TLS to secure FTP (FTPS) sessions. The certificate it presents has a fixed validity window, and once it expires, clients either refuse to connect or throw loud certificate-trust warnings. Unlike a web server behind automated tooling, a vsftpd box is often a quiet back-office file-transfer host that nobody touches until the certificate lapses and a partner integration fails.

The renewal itself is not hard, but two things trip people up: editing vsftpd.conf to point at the new files (a surprising number of runbooks leave the old filenames in place), and the PEM pass phrase prompt that blocks the daemon from starting unattended after reboot. We solve both below.

Before you start: prerequisites and a backup

Confirm you have root (or sudo) on the server, OpenSSL installed (openssl version), and the contact details for whoever issues certificates in your organisation (an internal CA team, or a public CA such as DigiCert, Sectigo, or Let's Encrypt). You will also need the existing certificate directory, commonly /etc/vsftpd/sslcert/ or /etc/ssl/private/.

Always back up the configuration and existing key material first. If anything goes wrong you can restore in seconds:

  1. Create a timestamped backup directory: mkdir -p /tmp/vsftpd_certren_$(date +%Y%m%d)
  2. Copy the certificate folder, preserving permissions: cp -rvp /etc/vsftpd/sslcert/* /tmp/vsftpd_certren_$(date +%Y%m%d)/
  3. Back up the main config too: cp -vp /etc/vsftpd/vsftpd.conf /tmp/vsftpd_certren_$(date +%Y%m%d)/

Use cp -rvp (recursive, verbose, preserve). A classic copy-paste trap is a stray en-dash in pasted runbooks — the shell will reject cp –rvp because that is not a real hyphen. Type the flags yourself.

Step 1: Generate a new private key

Move into the certificate directory and create a fresh 2048-bit RSA key (use 4096 if your security policy requires it):

  1. cd /etc/vsftpd/sslcert
  2. openssl genrsa -out server1-2026.key 2048

The older approach added -des3, which encrypts the key with a pass phrase. That is exactly what forces vsftpd to prompt for a PEM pass phrase on every start and breaks automatic boot. Unless your compliance rules mandate an encrypted key on disk, generate an unencrypted key as shown above so the daemon starts unattended.

If policy does require an encrypted key, you can strip the pass phrase later with openssl rsa -in encrypted.key -out plain.key, or keep it encrypted and accept that the service needs a manual passphrase entry (or a systemd credential helper) on each restart.

Step 2: Create the Certificate Signing Request (CSR)

Generate the CSR from the key. You will be prompted for the Distinguished Name fields:

  1. openssl req -new -key server1-2026.key -out server1-2026.csr

Fill in the fields accurately. The single most important one is the Common Name (CN), which must match the exact hostname clients use to connect (for example ftp.example.com). A mismatched CN is the number-one cause of post-renewal trust errors.

FieldExample valueNotes
Country Name (2 letter code)CAISO country code
State or Province NameOntarioFull name, no abbreviation
Locality NameTorontoCity
Organization NameExample Inc.Legal entity name
Organizational UnitInfrastructureOptional
Common Nameftp.example.comMust match the FQDN
Email Addressadmin@example.comOptional

You can safely leave the challenge password and optional company name blank by pressing Enter — they are legacy fields most CAs ignore. Verify the CSR before submitting it:

  1. openssl req -in server1-2026.csr -noout -text

Check that the Subject line shows the correct CN and organisation.

Step 3: Submit the CSR and obtain the signed certificate

Send server1-2026.csr to your certificate authority using their normal process (an internal portal with an authorisation code, or a public CA's web flow / ACME client). Never send the private key — only the CSR leaves the server.

The CA returns a signed certificate, usually a .cer, .crt, or .pem file. Many CAs also provide an intermediate / chain certificate. If your clients complain about an untrusted issuer after renewal, you almost certainly need to install that chain too. Copy the new certificate into the cert directory:

  1. cp -vp server1-2026.cer /etc/vsftpd/sslcert/

If you received a separate chain file, combine the server cert and chain into one bundle so vsftpd serves the full path to clients:

  1. cat server1-2026.cer intermediate-chain.cer > server1-2026-fullchain.cer

Step 4: Lock down file permissions

The private key must never be world-readable. Set tight ownership and permissions before you wire it into the config:

  1. chown root:root /etc/vsftpd/sslcert/server1-2026.key /etc/vsftpd/sslcert/server1-2026.cer
  2. chmod 600 /etc/vsftpd/sslcert/server1-2026.key
  3. chmod 644 /etc/vsftpd/sslcert/server1-2026.cer

On SELinux-enforcing systems, restore the correct security context so vsftpd is allowed to read the files: restorecon -Rv /etc/vsftpd/sslcert/.

Step 5: Point vsftpd.conf at the NEW certificate

This is the step where renewals most often go wrong. Open the config and update the two SSL path directives so they reference the new files, not the old ones:

  1. vim /etc/vsftpd/vsftpd.conf

Set the directives to the new filenames:

  • rsa_cert_file=/etc/vsftpd/sslcert/server1-2026.cer (or the -fullchain.cer bundle)
  • rsa_private_key_file=/etc/vsftpd/sslcert/server1-2026.key
  • ssl_enable=YES

A widespread bug in copied runbooks is leaving the old paths (e.g. server1-20140911.cer) in vsftpd.conf while believing the renewal is done. The service then keeps presenting the expired certificate. Double-check both lines reference the new file you just installed.

While you are in the file, modern, secure deployments should also enforce strong TLS by disabling the obsolete SSL protocols:

  • ssl_tlsv1_2=YES
  • ssl_sslv2=NO
  • ssl_sslv3=NO
  • require_ssl_reuse=NO (improves client compatibility)

Step 6: Validate the key and certificate match before restarting

Never restart blind. A mismatched key and certificate will refuse to load. Compare the modulus hashes — they must be identical:

  1. openssl x509 -noout -modulus -in /etc/vsftpd/sslcert/server1-2026.cer | openssl md5
  2. openssl rsa -noout -modulus -in /etc/vsftpd/sslcert/server1-2026.key | openssl md5

If the two hashes match, the pair is valid. Also confirm the new certificate's validity window and CN:

  1. openssl x509 -in /etc/vsftpd/sslcert/server1-2026.cer -noout -dates -subject

Step 7: Restart vsftpd and confirm it came up clean

Restart the daemon. On systemd hosts:

  1. systemctl restart vsftpd
  2. systemctl status vsftpd

On older SysV-init RHEL/CentOS hosts the equivalent is service vsftpd restart. If you generated an unencrypted key in Step 1, the service starts silently. If your key is still encrypted, you will see Enter PEM pass phrase: — and the service will hang on boot until someone types it. That is the behaviour you generally want to avoid on a production server.

Verification: prove the new certificate is being served

Configuration that looks right on disk still needs to be confirmed on the wire. Use OpenSSL's client to connect with explicit FTPS (STARTTLS over the FTP control channel) and read back the live certificate:

  1. openssl s_client -connect ftp.example.com:21 -starttls ftp

In the output, check the Certificate chain and the notAfter date — they should reflect the certificate you just installed, not the expired one. To see only the expiry quickly:

  1. echo | openssl s_client -connect ftp.example.com:21 -starttls ftp 2>/dev/null | openssl x509 -noout -dates

Finally, test a real FTPS login with a client such as lftp or FileZilla to confirm transfers succeed with no certificate warnings.

Common pitfalls and how to avoid them

  • vsftpd.conf still points at the old cert. The single most common failure. Update both rsa_cert_file and rsa_private_key_file.
  • Encrypted key blocks unattended startup. An -des3 key triggers the PEM pass phrase prompt and stops the service from starting on boot. Use an unencrypted key, protected by strict file permissions instead.
  • Key/certificate mismatch. Pasting the wrong file or mixing keys from two renewals. Always run the modulus-hash check in Step 6.
  • Missing intermediate chain. Clients report "unable to get local issuer certificate." Concatenate the chain into a full-chain file and point the config at it.
  • SELinux denials. The daemon can't read a freshly copied file. Run restorecon -Rv on the cert directory and check ausearch -m avc -ts recent if it still fails.
  • Wrong Common Name. A CN that doesn't match the connection hostname produces trust errors even with a valid, in-date certificate.
  • Stray en-dash in pasted commands. is not -; retype flags when a perfectly correct-looking command throws "invalid option."

A note on legacy versus modern certificate management

The manual genrsa-CSR-submit flow above remains the standard for internal/private CAs and for appliances that don't speak ACME. For internet-facing FTPS hosts, however, the modern approach is to automate issuance and renewal with a free Let's Encrypt certificate via certbot, then have a deploy hook copy the renewed fullchain.pem and privkey.pem into place and reload vsftpd. Automated 90-day renewals eliminate the "nobody noticed it expired" outage entirely. Whichever path you choose, the vsftpd-side configuration and verification steps are identical.

Key Takeaways

  • Back up the cert directory and vsftpd.conf before touching anything — recovery then takes seconds.
  • Generate an unencrypted private key (no -des3) so vsftpd starts unattended; secure it with chmod 600 instead.
  • The CSR's Common Name must match the FQDN clients connect to, or you'll get trust errors.
  • Update both rsa_cert_file and rsa_private_key_file to the new filenames — leaving old paths is the top renewal bug.
  • Verify on the wire with openssl s_client -starttls ftp before declaring the renewal done.

Frequently Asked Questions

How do I renew an SSL certificate for vsftpd without downtime?

Generate the new key and CSR, install the signed certificate alongside the old one, validate the key/cert pair, then update vsftpd.conf and restart. Existing transfers finish on the old session; new connections immediately use the new certificate, so there is effectively no outage.

Why does vsftpd ask for a PEM pass phrase when it starts?

Because the private key was created with encryption (the -des3 option). vsftpd must decrypt it at startup and prompts for the pass phrase, which blocks unattended boots. Regenerate the key without -des3, or strip the pass phrase with openssl rsa -in old.key -out new.key, and protect the file with chmod 600 instead.

How can I check which certificate vsftpd is actually serving?

Connect with explicit FTPS and read the live certificate: openssl s_client -connect host:21 -starttls ftp. Inspect the notAfter date and Subject CN in the output to confirm the new certificate is in use rather than the old one cached in the config.

Do I need to restart vsftpd after replacing the certificate?

Yes. vsftpd loads the certificate and key at startup, so a systemctl restart vsftpd (or service vsftpd restart on SysV hosts) is required for the new certificate to take effect. A simple reload is not sufficient for cert changes.

For more hands-on Linux sysadmin and DevOps walkthroughs, subscribe to our YouTube channel @explorenystream.