Skip to the content.

Security Best Practices

Security hardening and best practices for svp-provisioned sites.

Overview

svp implements security by default, but additional hardening can improve protection:


Built-in Security Features

What svp Provides

1. UFW Firewall

2. SSL/HTTPS

3. Basic Authentication

4. PHP Security

5. Database Security

6. File Permissions


Basic Authentication for Sites

Overview

HTTP Basic Authentication provides a simple, effective way to password-protect entire sites. This is particularly useful for:

Using the auth Command

svp makes it simple to enable, disable, or check authentication status for any domain.

Enable Authentication (Interactive)

The easiest way is to enable interactively, which will prompt for credentials:

sudo svp auth staging.example.com enable

You’ll be prompted to enter:

Enable Authentication (Non-Interactive)

For automation or scripting, provide credentials via flags:

sudo svp auth staging.example.com enable \
  --username admin \
  --password mySecurePassword123

Check Authentication Status

Verify if authentication is enabled for a domain:

sudo svp auth staging.example.com check

Output shows:

Disable Authentication

Remove authentication and allow public access:

sudo svp auth staging.example.com disable

This will:

How It Works

Behind the scenes:

  1. Installs apache2-utils if not present (for htpasswd command)
  2. Creates a .htpasswd file in the site directory
  3. Stores password using bcrypt hashing (secure)
  4. Updates Nginx configuration with auth_basic directives
  5. Reloads Nginx configuration (no restart needed)

Security notes:

Common Use Cases

Protect Staging Environment

# Set up staging with authentication from the start
sudo svp setup staging.mysite.com \
  --cms drupal \
  --le-email admin@mysite.com

# Enable authentication
sudo svp auth staging.mysite.com enable \
  --username client \
  --password preview2024

Secure Development Sites

# Enable auth on dev environment
sudo svp auth dev.mysite.com enable

# Share credentials with team
# Username: team
# Password: [as entered]

Temporary Protection

# Enable during development
sudo svp auth mysite.com enable

# Disable when ready for launch
sudo svp auth mysite.com disable

Best Practices

1. Use Strong Passwords

Generate secure passwords:

# Generate random password
openssl rand -base64 16

2. Combine with SSL/HTTPS

Always use HTTPS when using Basic Auth to encrypt credentials in transit:

sudo svp setup staging.mysite.com \
  --cms drupal \
  --le-email admin@mysite.com

sudo svp auth staging.mysite.com enable

3. Different Credentials per Environment

Use unique passwords for each environment:

sudo svp auth staging.mysite.com enable --username staging --password staging123
sudo svp auth dev.mysite.com enable --username dev --password dev456

4. Document Credentials Securely

Store credentials in a password manager, not in plain text files or emails.

5. Remove When Not Needed

Disable authentication when moving to production:

sudo svp auth mysite.com disable

Limitations

Troubleshooting

Authentication Not Working

  1. Check if enabled:
    sudo svp auth example.com check
    
  2. Verify Nginx configuration:
    sudo nginx -t
    sudo cat /etc/nginx/sites-available/example.com.conf | grep auth_basic
    
  3. Check .htpasswd file exists:
    ls -la /var/www/example.com/.htpasswd
    

Forgot Password

Simply re-enable authentication with new credentials:

sudo svp auth example.com enable --username admin --password newPassword123

Remove Old Credentials

Disable and re-enable:

sudo svp auth example.com disable
sudo svp auth example.com enable

Additional Security Hardening

1. SSH Security

Disable Root Login

sudo nano /etc/ssh/sshd_config

Set:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Restart SSH:

sudo systemctl restart sshd

SSH Key-Only Access

# On your local machine
ssh-keygen -t ed25519 -C "your-email@example.com"

# Copy to server
ssh-copy-id admin@your-server

# Test login
ssh admin@your-server

# Disable password auth (shown above)

Change SSH Port (Optional)

sudo nano /etc/ssh/sshd_config

Change:

Port 2222

Update firewall:

sudo ufw allow 2222/tcp
sudo ufw delete allow 22/tcp
sudo systemctl restart sshd

2. Fail2Ban

Install fail2ban to block brute force attempts:

sudo apt install fail2ban

Configure:

sudo nano /etc/fail2ban/jail.local

Add:

[sshd]
enabled = true
port = 22
maxretry = 3
bantime = 3600

[nginx-limit-req]
enabled = true
filter = nginx-limit-req
port = http,https
logpath = /var/log/nginx/*error.log

[nginx-noscript]
enabled = true
port = http,https
filter = nginx-noscript
logpath = /var/log/nginx/*access.log

Restart:

sudo systemctl restart fail2ban

Check bans:

sudo fail2ban-client status sshd

3. Automatic Security Updates

Enable unattended upgrades:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades

Configure:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Ensure enabled:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};

Web Application Security

1. Security Headers

Add to Nginx configuration:

sudo nano /etc/nginx/sites-available/example.com.conf

Add in server block:

# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Test and reload:

sudo nginx -t
sudo systemctl reload nginx

2. Rate Limiting

Prevent brute force attacks:

sudo nano /etc/nginx/nginx.conf

Add in http block:

limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

In site config:

location /user/login {
    limit_req zone=login burst=5 nodelay;
}

3. Hide Server Version

sudo nano /etc/nginx/nginx.conf

Add in http block:

server_tokens off;

Hide PHP version (already done by svp):

expose_php = Off

Database Security

1. Secure MariaDB

Run security script:

sudo mysql_secure_installation

Answer:

2. Database User Privileges

Verify minimal privileges:

mysql -e "SHOW GRANTS FOR 'drupal_example_com'@'localhost';"

Should only show:

GRANT USAGE ON *.* TO 'drupal_example_com'@'localhost'
GRANT ALL PRIVILEGES ON drupal_example_com.* TO 'drupal_example_com'@'localhost'

3. Backup Credentials Securely

Credentials in /etc/svp/sites/ must be protected:

# Verify permissions
ls -la /etc/svp/sites/*.db.txt

# Should show -rw------- (600)
# Fix if needed
sudo chmod 600 /etc/svp/sites/*.db.txt

Drupal Security

1. Security Modules

Install security modules:

cd /var/www/example.com
sudo -u admin composer require drupal/security_review
sudo -u admin composer require drupal/paranoia
drush-example.com en security_review paranoia -y

2. Security Review

Run security review:

drush-example.com security-review

Fix any issues found.

3. Restrict Admin Access

Restrict /admin to specific IPs:

sudo nano /etc/nginx/sites-available/example.com.conf

Add:

location ~ ^/admin {
    allow 1.2.3.4;      # Your IP
    allow 5.6.7.8;      # Office IP
    deny all;
    try_files $uri /index.php?$query_string;
}

4. Update Regularly

# Check for updates
drush-example.com pm:security

# Update modules
cd /var/www/example.com
sudo -u admin composer update --with-dependencies
drush-example.com updb -y
drush-example.com cr

WordPress Security

1. Security Plugins

Install security plugins:

cd /var/www/myblog.com
sudo -u admin wp plugin install wordfence --activate
sudo -u admin wp plugin install all-in-one-wp-security-and-firewall --activate

2. Disable File Editing

Add to wp-config.php:

define('DISALLOW_FILE_EDIT', true);

3. Limit Login Attempts

sudo -u admin wp plugin install limit-login-attempts-reloaded --activate

4. Hide wp-login.php

Use a security plugin to change login URL.

5. Update Regularly

cd /var/www/myblog.com
sudo -u admin wp core update
sudo -u admin wp plugin update --all
sudo -u admin wp theme update --all

File Security

1. Proper Permissions

Drupal:

cd /var/www/example.com
sudo chown -R admin:www-data .
sudo find . -type d -exec chmod 755 {} \;
sudo find . -type f -exec chmod 644 {} \;
sudo chmod 775 web/sites/default/files/
sudo chmod 444 web/sites/default/settings.php
sudo chmod 400 web/sites/default/settings.svp.php

WordPress:

cd /var/www/myblog.com
sudo chown -R admin:www-data .
sudo find . -type d -exec chmod 755 {} \;
sudo find . -type f -exec chmod 644 {} \;
sudo chmod 775 wp-content/uploads/
sudo chmod 400 wp-config.php

2. Protect Sensitive Files

Drupal - in Nginx config:

location ~ /\.ht {
    deny all;
}

location ~ /\. {
    deny all;
}

location ~ ^/sites/[^/]+/files/.*\.php$ {
    deny all;
}

WordPress - in Nginx config:

location ~ /\.ht {
    deny all;
}

location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
}

Monitoring & Logging

1. Monitor Logs

Nginx errors:

sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/example.com.error.log

PHP errors:

sudo tail -f /var/log/php8.3-fpm-example.com-error.log

Auth attempts:

sudo tail -f /var/log/auth.log

2. Log Rotation

Verify logrotate is configured:

cat /etc/logrotate.d/nginx
cat /etc/logrotate.d/php8.3-fpm

3. Intrusion Detection

Install AIDE:

sudo apt install aide
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Check for changes:

sudo aide --check

Backup Security

1. Encrypt Backups

# Backup and encrypt
tar -czf - /var/www/example.com | gpg --encrypt -r admin@example.com > backup.tar.gz.gpg

# Decrypt and restore
gpg --decrypt backup.tar.gz.gpg | tar -xzf -

2. Secure Backup Storage


Security Checklist

Initial Setup

Ongoing Maintenance

After Security Incident


Security Tools

Scan for Vulnerabilities

Drupal:

drush-example.com pm:security

WordPress:

cd /var/www/myblog.com
sudo -u admin wp plugin list --field=update

Test SSL Configuration

# Command line
echo | openssl s_client -connect example.com:443 -servername example.com

# Online test
# https://www.ssllabs.com/ssltest/

Enable or Update SSL

For sites without SSL or to renew certificates:

# Enable SSL for a site
sudo svp update-ssl example.com enable --le-email admin@example.com

# Check SSL status
sudo svp update-ssl example.com check

# Renew certificate
sudo svp update-ssl example.com renew

Port Scanning

Check what ports are exposed:

sudo nmap -sS -p 1-65535 localhost

Should only show: 22 (SSH), 80 (HTTP), 443 (HTTPS)


Incident Response

If Site is Compromised

  1. Isolate site:
    sudo systemctl stop nginx
    sudo systemctl stop php8.3-fpm
    
  2. Review logs:
    sudo grep -r "suspicious" /var/log/nginx/
    sudo grep -r "error" /var/log/php*/
    
  3. Check files:
    sudo find /var/www -name "*.php" -mtime -7
    
  4. Restore from backup:
    # Restore known good backup
    
  5. Reprovision if needed:
    sudo svp setup example.com --cms drupal
    
  6. Change all passwords:
    • Database
    • Admin users
    • SSH keys
    • API keys

← Reprovisioning Performance Tuning →