diff --git a/README.md b/README.md index af34121..d889b1e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ansible-WordPress-Nginx-Docker -This Ansible project automates the setup and configuration of an Ubuntu machine to host a WordPress website using Nginx, PHP, Docker, MySQL, and Redis. +This Ansible project automates the setup and configuration of an Ubuntu machine to host a WordPress website using Nginx, PHP, Docker, MySQL, and Redis. The Nginx vhost configuration is hardened for improved security. ## Features @@ -8,7 +8,7 @@ The Ansible playbook in this project will: 1. Update Ubuntu packages 2. Install Nginx -3. Configure Nginx +3. Configure Nginx with hardened vhost settings 4. Install PHP 5. Configure PHP 6. Install WordPress @@ -43,9 +43,7 @@ Run the playbook: ansible-playbook -i inventory/target.ini setup_server.yml ``` -After the playbook has run successfully, you should have a fully functional WordPress website running on your Ubuntu machine with Nginx, PHP, MySQL, and Redis. - -Please make sure to install Redis plugin which already has a pre-set configuration +After the playbook has run successfully, you should have a fully functional WordPress website running on your Ubuntu machine with Nginx, PHP, MySQL, and Redis, with a hardened Nginx vhost configuration. ## Variables diff --git a/roles/configure-nginx/files/vhost.conf.j2 b/roles/configure-nginx/files/vhost.conf.j2 index 1ace5f9..f0faf67 100644 --- a/roles/configure-nginx/files/vhost.conf.j2 +++ b/roles/configure-nginx/files/vhost.conf.j2 @@ -8,30 +8,30 @@ map $sent_http_content_type $expires { server { root /var/www/{{ vhost_name }}; - index index.php index.html index.htm; + index index.php; server_name {{ domain }}; listen 80; + #Cache settings expires $expires; + + #Upload max size client_max_body_size 50M; ErrorLog /var/log/nginx/{{ vhost_name }}-error.log CustomLog /var/log/nginx/{{ vhost_name }}-access.log combined - autoindex off; + #Disable directory listing + autoindex off; - location / { + location / { try_files $uri $uri/ @handler; - } - - location /admin { - try_files $uri $uri/ /admin/index.php?$args; - } + } location @handler { if (!-e $request_filename) { rewrite / /index.php last; } rewrite ^(.*.php)/ $1 last; - } + } location ~ \.php$ { include snippets/fastcgi-php.conf; @@ -39,4 +39,120 @@ server { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } + + #Disable access to wp-config.php + location ~* /(wp-config.php) { + deny all; + } + + #Limit XMLRPC access + location ~* /xmlrpc.php$ { + allow 172.0.1.1; + deny all; + } + + #Limit request types + if ($request_method !~ ^(GET|POST)$ ) { + return 444; + } + + #Limit direct PHP access + location ~* /(?:uploads|files|wp-content|wp-includes|akismet)/.*.php$ { + deny all; + access_log off; + log_not_found off; + } + + #Hide nginx version + server_tokens off; + + #Hide PHP version + fastcgi_hide_header X-Powered-By; + proxy_hide_header X-Powered-By; + + #Security headers + add_header X-Frame-Options SAMEORIGIN; #Comment it to allow iframe + add_header Strict-Transport-Security "max-age=31536000"; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + + # Disable logs for favicon and robots + location = /favicon.ico { + try_files /favicon.ico @empty; + access_log off; + log_not_found off; + expires max; + } + + location @empty { + empty_gif; + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + try_files $uri /index.php?$args; + } + + # Deny access to uploads that are not media files + location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ { + deny all; + } + + # Nginx common security + location ~* "(eval\()" { + deny all; + } + location ~* "(127\.0\.0\.1)" { + deny all; + } + location ~* "([a-z0-9]{2000})" { + deny all; + } + location ~* "(javascript\:)(.*)(\;)" { + deny all; + } + location ~* "(base64_encode)(.*)(\()" { + deny all; + } + location ~* "(GLOBALS|REQUEST)(=|\[|%)" { + deny all; + } + location ~* "(<|%3C).*script.*(>|%3)" { + deny all; + } + location ~ "(\\|\.\.\.|\.\./|~|`|<|>|\|)" { + deny all; + } + location ~* "(boot\.ini|etc/passwd|self/environ)" { + deny all; + } + location ~* "(thumbs?(_editor|open)?|tim(thumb)?)\.php" { + deny all; + } + location ~* "(\'|\")(.*)(drop|insert|md5|select|union)" { + deny all; + } + location ~* "(https?|ftp|php):/" { + deny all; + } + location ~* "(=\\\'|=\\%27|/\\\'/?)\." { + deny all; + } + location ~ "(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")" { + deny all; + } + location ~ "(~|`|<|>|:|;|%|\\|\s|\{|\}|\[|\]|\|)" { + deny all; + } + location ~* "/(=|\$&|_mm|(wp-)?config\.|cgi-|etc/passwd|muieblack)" { + deny all; + } + location ~* "(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)" { + deny all; + } + location ~* "/(^$|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell|config|settings|configuration)\.php" { + deny all; + } } \ No newline at end of file