Add ProFTPd setup
This commit is contained in:
@@ -15,7 +15,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
- Wildcard SSL Certificates support with DNS validation
|
||||
- Acme challenge validation with DNS API (Cloudflare, DigitalOcean, etc ..) on domain, subdomain, and wildcard
|
||||
- Flag `--letsencrypt=clean` to purge a previous SSL configuration
|
||||
- Support for Debian 10 (buster) in beta
|
||||
- Support for Debian 10 buster (testing - not ready for production)
|
||||
- Fail2ban with custom jails to secure WordPress & SSH
|
||||
- Variable `keylength` in /etc/wo/wo.conf to define letsencrypt certificate keylenght
|
||||
|
||||
#### Fixed
|
||||
|
||||
|
||||
22
README.md
22
README.md
@@ -59,7 +59,7 @@
|
||||
- Ubuntu 19.04 (Disco)
|
||||
- Debian 8 (Jessie)
|
||||
- Debian 9 (Stretch)
|
||||
- Debian 10 (Buster)
|
||||
- Debian 10 (Buster) - Not ready for production
|
||||
- Raspbian 9 (Stretch)
|
||||
|
||||
### Ports requirements
|
||||
@@ -78,20 +78,7 @@ sudo wo site create example.com --wp # Install required packages & setup Wor
|
||||
|
||||
## Must read
|
||||
|
||||
WordOps made some fundamental changes:
|
||||
|
||||
- We've deprecated the mail stack. As an alternative, you can take a look at [Mail-in-a-Box](https://github.com/mail-in-a-box/mailinabox), [iRedMail](https://www.iredmail.org/) or [Caesonia](https://github.com/vedetta-com/caesonia). As Roundcube alternative, there is [Rainloop](https://www.rainloop.net/) or [Afterlogic WebMail](https://github.com/afterlogic/webmail-lite-8)
|
||||
- Support for w3tc is dropped as a security precaution.
|
||||
- PHP 5.6 has been replaced by PHP 7.2 and PHP 7.0 has been replaced by PHP 7.3.
|
||||
- Nginx-ee package has been replaced by Nginx-wo (based on Nginx stable v1.16.0 with Brotli support)
|
||||
- HHVM stack has been removed
|
||||
- Let's Encrypt stack isn't based on letsencrypt-auto anymore, we use acme.sh to handle SSL certificates
|
||||
|
||||
If you are going to migrate from EasyEngine v3, here some important informations :
|
||||
|
||||
- Previous php upstreams in Nginx will not be overwritted
|
||||
- php5.6 and php7.0 will not be removed or uninstalled
|
||||
- previous Nginx common configurations will not be overwritted
|
||||
[From EasyEngine to WordOps](https://docs.wordops.net/about/from-easyengine-to-wordops/)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -135,9 +122,10 @@ wo site create example.com --proxy=127.0.0.1:3000 # create example.com with ngi
|
||||
### Sites secured with Let's Encrypt
|
||||
|
||||
```bash
|
||||
wo site create example.com --wp --letsencrypt # install wordpress & secure site with letsencrypt
|
||||
wo site create sub.example.com --wp --letsencrypt=subdomain # install wordpress and secure subdomain with letsencrypt
|
||||
wo site create example.com --wp --letsencrypt # wordpress secured with letsencrypt
|
||||
wo site create sub.example.com --wp --letsencrypt=subdomain # wordpress + letsencrypt subdomain
|
||||
wo site create site.tld --wp --letsencrypt --hsts # install wordpress & secure site with letsencrypt with HSTS
|
||||
wo site create site.tld --wp --letsencrypt=wildcard --dns=dns_cf # install wordpress & issue a wildcard SSL certificate with Cloudflare DNS API
|
||||
```
|
||||
|
||||
## Update WordOps
|
||||
|
||||
@@ -79,6 +79,8 @@ class WOStackController(CementBaseController):
|
||||
dict(help='Install Redis', action='store_true')),
|
||||
(['--phpredisadmin'],
|
||||
dict(help='Install phpRedisAdmin', action='store_true')),
|
||||
(['--proftpd'],
|
||||
dict(help='Install ProFTPd', action='store_true')),
|
||||
]
|
||||
usage = "wo stack (command) [options]"
|
||||
|
||||
@@ -1103,6 +1105,37 @@ class WOStackController(CementBaseController):
|
||||
msg="Adding Fail2ban into Git")
|
||||
WOService.reload_service(self, 'fail2ban')
|
||||
|
||||
if set(["proftpd-basic"]).issubset(set(apt_packages)):
|
||||
if os.path.isfile("/etc/proftpd/proftpd.conf"):
|
||||
Log.debug(self, "Setting up Proftpd configuration")
|
||||
WOFileUtils.searchreplace(self, "/etc/proftpd/"
|
||||
"proftpd.conf",
|
||||
"# DefaultRoot",
|
||||
"DefaultRoot")
|
||||
WOFileUtils.searchreplace(self, "/etc/proftpd/"
|
||||
"proftpd.conf",
|
||||
"# RequireValidShell",
|
||||
"RequireValidShell")
|
||||
WOFileUtils.searchreplace(self, "/etc/proftpd/"
|
||||
"proftpd.conf",
|
||||
"# PassivePorts "
|
||||
" "
|
||||
"49152 65534",
|
||||
"PassivePorts "
|
||||
" "
|
||||
" 49000 50000")
|
||||
|
||||
if WOAptGet.is_installed(self, 'ufw'):
|
||||
try:
|
||||
WOShellExec.cmd_exec(self, "ufw allow "
|
||||
"49000:50000/tcp")
|
||||
except CommandExecutionError as e:
|
||||
Log.error(self, "Unable to add UFW rules")
|
||||
|
||||
WOGit.add(self, ["/etc/proftpd"],
|
||||
msg="Adding ProFTPd into Git")
|
||||
WOService.reload_service(self, 'proftpd')
|
||||
|
||||
if (packages):
|
||||
if any('/usr/local/bin/wp' == x[1] for x in packages):
|
||||
Log.debug(self, "Setting Privileges"
|
||||
@@ -1421,7 +1454,7 @@ class WOStackController(CementBaseController):
|
||||
(not self.app.pargs.dashboard) and
|
||||
(not self.app.pargs.fail2ban) and
|
||||
(not self.app.pargs.adminer) and (not self.app.pargs.utils) and
|
||||
(not self.app.pargs.redis) and
|
||||
(not self.app.pargs.redis) and (not self.app.pargs.proftpd) and
|
||||
(not self.app.pargs.phpredisadmin) and
|
||||
(not self.app.pargs.php73)):
|
||||
self.app.pargs.web = True
|
||||
@@ -1432,6 +1465,7 @@ class WOStackController(CementBaseController):
|
||||
self.app.pargs.admin = True
|
||||
self.app.pargs.php73 = True
|
||||
self.app.pargs.redis = True
|
||||
self.app.pargs.proftpd = True
|
||||
|
||||
if self.app.pargs.web:
|
||||
self.app.pargs.nginx = True
|
||||
@@ -1547,6 +1581,15 @@ class WOStackController(CementBaseController):
|
||||
Log.debug(self, "Fail2ban already installed")
|
||||
Log.info(self, "Fail2ban already installed")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
Log.debug(self, "Setting apt_packages variable for ProFTPd")
|
||||
if not WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
apt_packages = apt_packages + ["proftpd-basic"]
|
||||
else:
|
||||
Log.debug(self, "ProFTPd already installed")
|
||||
Log.info(self, "ProFTPd already installed")
|
||||
|
||||
# PHPMYADMIN
|
||||
if self.app.pargs.phpmyadmin:
|
||||
if not os.path.isdir('/var/www/22222/htdocs/db/pma'):
|
||||
@@ -1741,7 +1784,7 @@ class WOStackController(CementBaseController):
|
||||
(not self.app.pargs.wpcli) and (not self.app.pargs.phpmyadmin) and
|
||||
(not self.app.pargs.adminer) and (not self.app.pargs.utils) and
|
||||
(not self.app.pargs.composer) and (not self.app.pargs.netdata) and
|
||||
(not self.app.pargs.fail2ban) and
|
||||
(not self.app.pargs.fail2ban) and (not self.app.pargs.proftpd) and
|
||||
(not self.app.pargs.all) and (not self.app.pargs.redis) and
|
||||
(not self.app.pargs.phpredisadmin)):
|
||||
self.app.pargs.web = True
|
||||
@@ -1813,8 +1856,19 @@ class WOStackController(CementBaseController):
|
||||
|
||||
# fail2ban
|
||||
if self.app.pargs.fail2ban:
|
||||
Log.debug(self, "Remove apt_packages variable of Fail2ban")
|
||||
apt_packages = apt_packages + WOVariables.wo_fail2ban
|
||||
if WOAptGet.is_installed(self, 'fail2ban'):
|
||||
Log.debug(self, "Remove apt_packages variable of Fail2ban")
|
||||
apt_packages = apt_packages + WOVariables.wo_fail2ban
|
||||
else:
|
||||
Log.error(self, "Fail2ban not found")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
Log.debug(self, "Remove apt_packages variable for ProFTPd")
|
||||
apt_packages = apt_packages + ["proftpd-basic"]
|
||||
else:
|
||||
Log.error(self, "ProFTPd not found")
|
||||
|
||||
# WPCLI
|
||||
if self.app.pargs.wpcli:
|
||||
@@ -1920,7 +1974,7 @@ class WOStackController(CementBaseController):
|
||||
(not self.app.pargs.wpcli) and (not self.app.pargs.phpmyadmin) and
|
||||
(not self.app.pargs.adminer) and (not self.app.pargs.utils) and
|
||||
(not self.app.pargs.composer) and (not self.app.pargs.netdata) and
|
||||
(not self.app.pargs.fail2ban) and
|
||||
(not self.app.pargs.fail2ban) and (not self.app.pargs.proftpd)
|
||||
(not self.app.pargs.all) and (not self.app.pargs.redis) and
|
||||
(not self.app.pargs.phpredisadmin)):
|
||||
self.app.pargs.web = True
|
||||
@@ -1981,8 +2035,19 @@ class WOStackController(CementBaseController):
|
||||
|
||||
# fail2ban
|
||||
if self.app.pargs.fail2ban:
|
||||
Log.debug(self, "Remove apt_packages variable of Fail2ban")
|
||||
apt_packages = apt_packages + WOVariables.wo_fail2ban
|
||||
if WOAptGet.is_installed(self, 'fail2ban'):
|
||||
Log.debug(self, "Purge apt_packages variable of Fail2ban")
|
||||
apt_packages = apt_packages + WOVariables.wo_fail2ban
|
||||
else:
|
||||
Log.error(self, "Fail2ban not found")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
Log.debug(self, "Purge apt_packages variable for ProFTPd")
|
||||
apt_packages = apt_packages + ["proftpd-basic"]
|
||||
else:
|
||||
Log.error(self, "ProFTPd not found")
|
||||
|
||||
# WP-CLI
|
||||
if self.app.pargs.wpcli:
|
||||
|
||||
@@ -4,6 +4,7 @@ from wo.core.services import WOService
|
||||
from wo.core.logging import Log
|
||||
from wo.core.variables import WOVariables
|
||||
from wo.core.aptget import WOAptGet
|
||||
import os
|
||||
|
||||
|
||||
class WOStackStatusController(CementBaseController):
|
||||
@@ -22,6 +23,7 @@ class WOStackStatusController(CementBaseController):
|
||||
self.app.pargs.mysql or
|
||||
self.app.pargs.redis or
|
||||
self.app.pargs.fail2ban or
|
||||
self.app.pargs.proftpd or
|
||||
self.app.pargs.netdata):
|
||||
self.app.pargs.nginx = True
|
||||
self.app.pargs.php = True
|
||||
@@ -74,6 +76,20 @@ class WOStackStatusController(CementBaseController):
|
||||
else:
|
||||
Log.info(self, "fail2ban is not installed")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
services = services + ['proftpd']
|
||||
else:
|
||||
Log.info(self, "ProFTPd is not installed")
|
||||
|
||||
# netdata
|
||||
if self.app.pargs.netdata:
|
||||
if os.path.isdir("/opt/netdata"):
|
||||
services = services + ['netdata']
|
||||
else:
|
||||
Log.info(self, "Netdata is not installed")
|
||||
|
||||
for service in services:
|
||||
Log.debug(self, "Starting service: {0}".format(service))
|
||||
WOService.start_service(self, service)
|
||||
@@ -86,17 +102,21 @@ class WOStackStatusController(CementBaseController):
|
||||
self.app.pargs.php73 or
|
||||
self.app.pargs.mysql or
|
||||
self.app.pargs.fail2ban or
|
||||
self.app.pargs.netdata or
|
||||
self.app.pargs.proftpd or
|
||||
self.app.pargs.redis):
|
||||
self.app.pargs.nginx = True
|
||||
self.app.pargs.php = True
|
||||
self.app.pargs.mysql = True
|
||||
|
||||
# nginx
|
||||
if self.app.pargs.nginx:
|
||||
if (WOAptGet.is_installed(self, 'nginx-custom')):
|
||||
services = services + ['nginx']
|
||||
else:
|
||||
Log.info(self, "Nginx is not installed")
|
||||
|
||||
# php7.2
|
||||
if self.app.pargs.php:
|
||||
if WOAptGet.is_installed(self, 'php7.2-fpm'):
|
||||
services = services + ['php7.2-fpm']
|
||||
@@ -108,12 +128,14 @@ class WOStackStatusController(CementBaseController):
|
||||
else:
|
||||
Log.info(self, "PHP7.3-FPM is not installed")
|
||||
|
||||
# php7.3
|
||||
if self.app.pargs.php73:
|
||||
if WOAptGet.is_installed(self, 'php7.3-fpm'):
|
||||
services = services + ['php7.3-fpm']
|
||||
else:
|
||||
Log.info(self, "PHP7.3-FPM is not installed")
|
||||
|
||||
# mysql
|
||||
if self.app.pargs.mysql:
|
||||
if ((WOVariables.wo_mysql_host is "localhost") or
|
||||
(WOVariables.wo_mysql_host is "127.0.0.1")):
|
||||
@@ -127,18 +149,34 @@ class WOStackStatusController(CementBaseController):
|
||||
Log.warn(self, "Remote MySQL found, "
|
||||
"Unable to check MySQL service status")
|
||||
|
||||
# redis
|
||||
if self.app.pargs.redis:
|
||||
if WOAptGet.is_installed(self, 'redis-server'):
|
||||
services = services + ['redis-server']
|
||||
else:
|
||||
Log.info(self, "Redis server is not installed")
|
||||
|
||||
# fail2ban
|
||||
if self.app.pargs.fail2ban:
|
||||
if WOAptGet.is_installed(self, 'fail2ban'):
|
||||
services = services + ['fail2ban']
|
||||
else:
|
||||
Log.info(self, "fail2ban is not installed")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
services = services + ['proftpd']
|
||||
else:
|
||||
Log.info(self, "ProFTPd is not installed")
|
||||
|
||||
# netdata
|
||||
if self.app.pargs.netdata:
|
||||
if os.path.isdir("/opt/netdata"):
|
||||
services = services + ['netdata']
|
||||
else:
|
||||
Log.info(self, "Netdata is not installed")
|
||||
|
||||
for service in services:
|
||||
Log.debug(self, "Stopping service: {0}".format(service))
|
||||
WOService.stop_service(self, service)
|
||||
@@ -150,7 +188,8 @@ class WOStackStatusController(CementBaseController):
|
||||
if not (self.app.pargs.nginx or self.app.pargs.php or
|
||||
self.app.pargs.php73 or
|
||||
self.app.pargs.mysql or
|
||||
self.app.pargs.memcached or
|
||||
self.app.pargs.netdata or
|
||||
self.app.pargs.proftpd or
|
||||
self.app.pargs.redis or
|
||||
self.app.pargs.fail2ban):
|
||||
self.app.pargs.nginx = True
|
||||
@@ -206,6 +245,20 @@ class WOStackStatusController(CementBaseController):
|
||||
else:
|
||||
Log.info(self, "fail2ban is not installed")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
services = services + ['proftpd']
|
||||
else:
|
||||
Log.info(self, "ProFTPd is not installed")
|
||||
|
||||
# netdata
|
||||
if self.app.pargs.netdata:
|
||||
if os.path.isdir("/opt/netdata"):
|
||||
services = services + ['netdata']
|
||||
else:
|
||||
Log.info(self, "Netdata is not installed")
|
||||
|
||||
for service in services:
|
||||
Log.debug(self, "Restarting service: {0}".format(service))
|
||||
WOService.restart_service(self, service)
|
||||
@@ -217,6 +270,8 @@ class WOStackStatusController(CementBaseController):
|
||||
if not (self.app.pargs.nginx or self.app.pargs.php or
|
||||
self.app.pargs.php73 or
|
||||
self.app.pargs.mysql or
|
||||
self.app.pargs.netdata or
|
||||
self.app.pargs.proftpd or
|
||||
self.app.pargs.redis or
|
||||
self.app.pargs.fail2ban):
|
||||
self.app.pargs.nginx = True
|
||||
@@ -271,6 +326,20 @@ class WOStackStatusController(CementBaseController):
|
||||
else:
|
||||
Log.info(self, "fail2ban is not installed")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
services = services + ['proftpd']
|
||||
else:
|
||||
Log.info(self, "ProFTPd is not installed")
|
||||
|
||||
# netdata
|
||||
if self.app.pargs.netdata:
|
||||
if os.path.isdir("/opt/netdata"):
|
||||
services = services + ['netdata']
|
||||
else:
|
||||
Log.info(self, "Netdata is not installed")
|
||||
|
||||
for service in services:
|
||||
if WOService.get_service_status(self, service):
|
||||
Log.info(self, "{0:10}: {1}".format(service, "Running"))
|
||||
@@ -282,6 +351,8 @@ class WOStackStatusController(CementBaseController):
|
||||
if not (self.app.pargs.nginx or self.app.pargs.php or
|
||||
self.app.pargs.php73 or
|
||||
self.app.pargs.mysql or
|
||||
self.app.pargs.netdata or
|
||||
self.app.pargs.proftpd or
|
||||
self.app.pargs.redis or
|
||||
self.app.pargs.fail2ban):
|
||||
self.app.pargs.nginx = True
|
||||
@@ -337,6 +408,20 @@ class WOStackStatusController(CementBaseController):
|
||||
else:
|
||||
Log.info(self, "fail2ban is not installed")
|
||||
|
||||
# proftpd
|
||||
if self.app.pargs.proftpd:
|
||||
if WOAptGet.is_installed(self, 'proftpd-basic'):
|
||||
services = services + ['proftpd']
|
||||
else:
|
||||
Log.info(self, "ProFTPd is not installed")
|
||||
|
||||
# netdata
|
||||
if self.app.pargs.netdata:
|
||||
if os.path.isdir("/opt/netdata"):
|
||||
services = services + ['netdata']
|
||||
else:
|
||||
Log.info(self, "Netdata is not installed")
|
||||
|
||||
for service in services:
|
||||
Log.debug(self, "Reloading service: {0}".format(service))
|
||||
WOService.reload_service(self, service)
|
||||
|
||||
@@ -40,6 +40,22 @@ location /wp-content/uploads {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
# webp rewrite rules for EWWW testing image
|
||||
location /wp-content/plugins/ewww-image-optimizer/images {
|
||||
location ~ \.(png|jpe?g)$ {
|
||||
add_header Vary "Accept-Encoding";
|
||||
add_header "Access-Control-Allow-Origin" "*";
|
||||
add_header Cache-Control "public, no-transform";
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
expires max;
|
||||
try_files $uri$webp_suffix $uri =404;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
#Prevent Direct Access Of PHP Files From Web Browsers
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
# Deny access to any files with a .php extension in the uploads directory
|
||||
# Works in sub-directory installs and also in multisite network
|
||||
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
|
||||
|
||||
@@ -21,7 +21,7 @@ location = /robots.txt {
|
||||
}
|
||||
# fallback for robots.txt with default wordpress rules
|
||||
location @robots {
|
||||
return 200 "User-agent: *\nDisallow: /wp-admin/\nAllow: /wp-admin/admin-ajax.php\n";
|
||||
return 200 "User-agent: *\nDisallow: /wp-admin/\nAllow: /wp-admin/admin-ajax.php\n";
|
||||
}
|
||||
# webp rewrite rules for jpg and png images
|
||||
# try to load alternative image.png.webp before image.png
|
||||
@@ -36,7 +36,23 @@ location /wp-content/uploads {
|
||||
try_files $uri$webp_suffix $uri =404;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
#Prevent Direct Access Of PHP Files From Web Browsers
|
||||
#Prevent Direct Access Of PHP Files From Web Browsers
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
# webp rewrite rules for EWWW testing image
|
||||
location /wp-content/plugins/ewww-image-optimizer/images {
|
||||
location ~ \.(png|jpe?g)$ {
|
||||
add_header Vary "Accept-Encoding";
|
||||
add_header "Access-Control-Allow-Origin" "*";
|
||||
add_header Cache-Control "public, no-transform";
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
expires max;
|
||||
try_files $uri$webp_suffix $uri =404;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
#Prevent Direct Access Of PHP Files From Web Browsers
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user