SSL Certificate renewal for a VSFTP server on Linux
— ny_wk

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:
- Create a timestamped backup directory:
mkdir -p /tmp/vsftpd_certren_$(date +%Y%m%d) - Copy the certificate folder, preserving permissions:
cp -rvp /etc/vsftpd/sslcert/* /tmp/vsftpd_certren_$(date +%Y%m%d)/ - 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):
cd /etc/vsftpd/sslcertopenssl 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:
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.
| Field | Example value | Notes |
| Country Name (2 letter code) | CA | ISO country code |
| State or Province Name | Ontario | Full name, no abbreviation |
| Locality Name | Toronto | City |
| Organization Name | Example Inc. | Legal entity name |
| Organizational Unit | Infrastructure | Optional |
| Common Name | ftp.example.com | Must match the FQDN |
| Email Address | admin@example.com | Optional |
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:
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:
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:
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:
chown root:root /etc/vsftpd/sslcert/server1-2026.key /etc/vsftpd/sslcert/server1-2026.cerchmod 600 /etc/vsftpd/sslcert/server1-2026.keychmod 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:
vim /etc/vsftpd/vsftpd.conf
Set the directives to the new filenames:
rsa_cert_file=/etc/vsftpd/sslcert/server1-2026.cer(or the-fullchain.cerbundle)rsa_private_key_file=/etc/vsftpd/sslcert/server1-2026.keyssl_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=YESssl_sslv2=NOssl_sslv3=NOrequire_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:
openssl x509 -noout -modulus -in /etc/vsftpd/sslcert/server1-2026.cer | openssl md5openssl 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:
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:
systemctl restart vsftpdsystemctl 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:
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:
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_fileandrsa_private_key_file. - Encrypted key blocks unattended startup. An
-des3key 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 -Rvon the cert directory and checkausearch -m avc -ts recentif 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.confbefore touching anything — recovery then takes seconds. - Generate an unencrypted private key (no
-des3) so vsftpd starts unattended; secure it withchmod 600instead. - The CSR's Common Name must match the FQDN clients connect to, or you'll get trust errors.
- Update both
rsa_cert_fileandrsa_private_key_fileto the new filenames — leaving old paths is the top renewal bug. - Verify on the wire with
openssl s_client -starttls ftpbefore 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.