{"id":2353,"date":"2026-11-02T09:26:46","date_gmt":"2026-11-02T00:26:46","guid":{"rendered":"https:\/\/blog.coppe.jp\/?p=2353"},"modified":"2026-11-02T17:49:04","modified_gmt":"2026-11-02T08:49:04","slug":"sakura-vps-security-hardening","status":"publish","type":"post","link":"https:\/\/blog.coppe.jp\/en\/2026\/11\/02\/sakura-vps-security-hardening\/","title":{"rendered":"Tell BLOCK from detection in Sakura VPS SiteGuard logs"},"content":{"rendered":"<p class=\"wp-block-paragraph\">In recent weeks, a series of unauthorized web access incidents have come to light, starting with Park24 Group&#039;s Times Car service and including a large-scale security incident in which GMO Internet was subjected to a cyberattack.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">During one of those weeks, I took a look at the recent logs for SiteGuard Lite on my Sakura VPS. What I found were requests directly accessing the names of configuration files and environment variable files, requests attempting to traverse directories, attacks targeting other products not running on this server, and unfamiliar HTTP methods.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the lines I checked, the verdict was BLOCK. The aim was to reduce entry points, so that traffic currently stopped in front of the app would not spread if it got through.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The environment is Sakura VPS, RHEL-based, Apache httpd, firewalld, PHP (php-fpm), and SiteGuard Lite. Multiple websites, including WordPress and EC-CUBE, reside on it. The following hostnames and IP addresses are all examples.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to read logs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">From one line, I kept only these four things.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When it arrived<\/li>\n\n\n\n<li>What type of URL is it? (e.g., configuration file name, administrative path, unusually long query, etc.)<\/li>\n\n\n\n<li>Is the judgment BLOCK, or is it just detection and letting it through?<\/li>\n\n\n\n<li>How many requests came from the same source in a short time<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A &quot;BLOCK&quot; status means the request did not reach the application. A high number of BLOCK requests indicates active searching, not proof of intrusion.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This article will distinguish between different stopping methods using the following three terms.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>BLOCK<\/strong> ...SiteGuard rejects it before it reaches the app.<\/li>\n\n\n\n<li><strong>403<\/strong> ...Apache rejects the request.<\/li>\n\n\n\n<li><strong>DROP<\/strong> ...firewalld drops the packet, so from the sender it looks as if nothing arrived<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"920\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading.png\" alt=\"A diagram splitting one log line into when, which URL, the verdict, and the same source. Addresses are examples.\" class=\"wp-image-2355\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading.png 1600w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading-300x173.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading-1024x589.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading-768x442.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading-1536x883.png 1536w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/01-log-reading-18x10.png 18w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">These are the four things to extract from a single line of the log. The address and hostname are just examples.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Policy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The primary method will be using SiteGuard&#039;s official signature. The IP list is kept as a supplement. Since the source changes daily, manually tracking the list will not be the main countermeasure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The actions taken were in the following order, starting with those closest to the log.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Close files that do not need to be made public.<\/li>\n\n\n\n<li>Make unused hostnames invisible from the outside.<\/li>\n\n\n\n<li>Put the app on a security release in its own product line, and limit the app admin screen to the work network<\/li>\n\n\n\n<li>Remove the version string from the response header.<\/li>\n\n\n\n<li>For a while, automatically keep away IPs that repeat the same failures<\/li>\n\n\n\n<li>Automatically apply only OS security updates without requiring a restart.<\/li>\n\n\n\n<li>DROP only the sources that stand out, as a supplement<\/li>\n\n\n\n<li>Restrict SiteGuard&#039;s management port to only the work line.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"780\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers.png\" alt=\"Layers a request passes through: firewalld, SiteGuard, unknown hosts, allowed IPs, patches, and the app.\" class=\"wp-image-2356\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers.png 1600w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers-300x146.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers-1024x499.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers-768x374.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers-1536x749.png 1536w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/02-layers-18x9.png 18w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">Most of these requests stop at SiteGuard. firewalld is only a supplement for sources that stand out.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">1. Close information that had been left exposed.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Requesting the server default document root by raw IP showed that <code data-no-translation=\"\">info.php<\/code> was returning 200. The body was phpinfo, listing the PHP version, paths, and loaded modules. It had been left there for diagnostics, so I moved the file and returned 403 for that path. I also changed the default document root so it does not show its contents.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I also checked each site's <code data-no-translation=\"\">.env<\/code> and <code data-no-translation=\"\">web.config<\/code> from the outside, using only the status code. All were 403 or 404, and no body was returned. That confirmed they were closed. I added no further deny rule.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Only the HTTP methods necessary for the site were retained. Methods not used for normal browsing or form submission are rejected by Apache.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"701\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/03-forbidden.png\" alt=\"A browser showing Forbidden for a direct request to the server IP. The address is hidden.\" class=\"wp-image-2357\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/03-forbidden.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/03-forbidden-300x205.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/03-forbidden-768x526.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/03-forbidden-18x12.png 18w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">Entering an IP address directly will result in a Forbidden error. Previously, internal PHP information was displayed here.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">2. Unused sites and hosts with only a name.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For sites that weren&#039;t functioning, I decommissioned them along with their document roots, virtual hosts, and unnecessary databases. The databases and users of the sites I kept were not touched.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I kept the DNS wildcard.<code data-no-translation=\"\">*<\/code> As long as this exists, deleted names and non-existent subdomains will still be resolved to this server. Therefore, HTTPS connections from hosts other than those I know will result in a 403 error. This is to prevent unknown names from responding with the server&#039;s default certificate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before and after the work, I checked that the public sites returned HTTP 200, and checked the certificate issuer and expiry.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"940\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns.png\" alt=\"A diagram of wildcard DNS: the name resolves, and unknown hosts get 403. Hostnames are examples.\" class=\"wp-image-2358\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns.png 1600w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns-300x176.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns-1024x602.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns-768x451.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns-1536x902.png 1536w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/04-wildcard-dns-18x12.png 18w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">The name still resolves. Open only hosts that exist, and return 403 for the rest. Hostnames are examples.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">3. App-side entry point<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">EC-CUBE was moved to a security release in its own product line. The change was the multi-factor authentication around the admin screen. I put production into a short maintenance window, took a database dump, applied the official diff, updated the schema, then ended maintenance. I checked the version string, related files, and the front and admin login responses, then called it done. Customizations such as addresses and invoices stayed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress core and plugins were already current at the time. The only addition was rejecting <code data-no-translation=\"\">xmlrpc.php<\/code>. That unused path is an easy route for pingbacks and brute force, so I returned 403.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The EC-CUBE admin panel had an empty field for allowed connections. I entered only the IP address of my work network here. On days when I connect from a different network, I add that IP address and clear the cache.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I restricted access to the temporary PHP file I had been using for work, which was previously left unauthenticated, to only the same network connection. Although it wasn&#039;t a file that executed commands, it allowed me to see its internal paths and the progress of the work. I deleted it once I was finished.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"615\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-deny.png\" alt=\"On a network that is not allowed, the app admin screen says access is denied.\" class=\"wp-image-2360\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-deny.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-deny-300x180.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-deny-768x461.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-deny-18x12.png 18w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">The app&#039;s management screen will not open from unauthorized connections. The site name and address are hidden.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-allow.png\" alt=\"From the work network, the app login screen opens.\" class=\"wp-image-2359\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-allow.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-allow-300x180.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-allow-768x462.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/05-admin-allow-18x12.png 18w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">The login screen is accessible from the work network.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">4. Do not include the version in the header.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">By default, PHP adds <code data-no-translation=\"\">X-Powered-By: PHP\/x.x.x<\/code> to the response headers.<code data-no-translation=\"\">expose_php=Off<\/code>. After reloading php-fpm, this header disappears. The page does not change. This does not close the vulnerability. It only makes the version harder to guess.<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\">expose_php = Off<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">5. Leave the repetition to fail2ban.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I installed fail2ban and set firewalld to DROP, for a while, IPs that keep failing or probing in the logs. I enabled these six jails.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Jail<\/th><th>What it watches<\/th><\/tr><\/thead><tbody><tr><td>sshd<\/td><td>SSH login failed<\/td><\/tr><tr><td>apache-auth<\/td><td>Failures such as Basic Authentication<\/td><\/tr><tr><td>apache-badbots<\/td><td>Known malicious crawlers<\/td><\/tr><tr><td>apache-noscript<\/td><td>Probing for scripts that do not exist<\/td><\/tr><tr><td>apache-overflows<\/td><td>Unusually long URLs, etc.<\/td><\/tr><tr><td>recidive<\/td><td>Block IP addresses that have been blocked multiple times for an extended period.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">I added the work network to <code data-no-translation=\"\">ignoreip<\/code> so my own actions would not lock me out.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A side effect is that legitimate users can be cut off for a while. A company or carrier egress IP is sometimes shared with unrelated people. After enabling it, use <code data-no-translation=\"\">fail2ban-client status<\/code> to check the counts, and loosen or remove a jail that looks wrong.<\/p>\n\n\n\n<figure class=\"text-figure\"><div class=\"step-row\"><div class=\"step\"><p class=\"step__n\">01<\/p><p class=\"step__mark\">\ud83d\udeaa<\/p><p class=\"step__title\">Few failures<\/p><p class=\"step__note\">Still let it through<\/p><\/div><div class=\"step\"><p class=\"step__n\">02<\/p><p class=\"step__mark\">\u26a0\ufe0f<\/p><p class=\"step__title\">Repeat in a short period of time<\/p><p class=\"step__note\">The same sender continues<\/p><\/div><div class=\"step\"><p class=\"step__n\">03<\/p><p class=\"step__mark\">\ud83d\udd12<\/p><p class=\"step__title\">Close for a while<\/p><p class=\"step__note\">Temporarily DROP<\/p><\/div><\/div><figcaption>If the same sender repeatedly fails in a short period of time, I&#039;ll keep the door closed for a while.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">6. Automate only the OS security updates.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code data-no-translation=\"\">dnf-automatic<\/code> and apply only security updates automatically. I do not reboot automatically after a kernel update. The scope is narrower than updating everything, but it avoids an unplanned reboot taking the site down.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Block frequently occurring IP addresses as a backup.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I added only the source that stood out in the most recent logs to both SiteGuard&#039;s connection rejection and firewalld&#039;s DROP command. I didn&#039;t add country-specific rejections because there are legitimate access attempts from overseas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is an initial step. Even if the same address continues to appear in the log afterward, if it&#039;s already blocked, we don&#039;t manually move each entry to the DROP list. Our primary focus remains on the official signature and its automatic updates. Even within the same campaign, the sender changes frequently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We don&#039;t blindly apply the publicly available list of notorious IP addresses. Older addresses and shared cloud ranges can sometimes inadvertently include legitimate communications. Manually adding only those entries that clearly indicate a scan from our own server logs is sufficient.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. SiteGuard&#039;s management port is only for the work line.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The SiteGuard admin screen listens on port <code data-no-translation=\"\">9443<\/code>. It is open only to the work network and localhost. Connections from anywhere else time out. Ports 80 and 443 of the public site are unchanged.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This screen uses a different certificate than the one used by the production site&#039;s Let&#039;s Encrypt. If you open it by directly specifying the IP address, your browser will display a certificate warning. You can open it by proceeding to the details from an authorized connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">From elsewhere, reach it with an SSH local forward.<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\"><code data-no-translation=\"\">ssh -L 9443:127.0.0.1:9443 user@your-server<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In a local browser, open <code data-no-translation=\"\">https:\/\/127.0.0.1:9443\/<\/code> . A certificate warning is likely. If the work-network IP changes, update the firewalld allow rule. Forgetting that locks out only you.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"615\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-timeout.png\" alt=\"A screen showing that the admin port times out from a network that is not allowed.\" class=\"wp-image-2364\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-timeout.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-timeout-300x180.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-timeout-768x461.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-timeout-18x12.png 18w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">Connections from unauthorized lines will time out.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"594\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-login.png\" alt=\"The SiteGuard login screen after continuing past the certificate warning.\" class=\"wp-image-2362\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-login.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-login-300x174.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-login-768x446.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-login-18x10.png 18w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">On authorized connections, the login screen appears after exceeding the certificate warning. The address is hidden.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"709\" src=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-open.png\" alt=\"The SiteGuard admin screen after login. The hostname and source list are hidden.\" class=\"wp-image-2363\" srcset=\"https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-open.png 1024w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-open-300x208.png 300w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-open-768x532.png 768w, https:\/\/blog.coppe.jp\/app\/uploads\/2026\/11\/07-admin-open-18x12.png 18w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption coppe-img-caption coppe-i18n\" data-caption-source=\"figcaption\" data-no-translation=\"\">The management screen after logging in. Only the signature breakdown is visible.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Left for later<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The following three were considered but ultimately rejected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Additional IPv6 restrictions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This VPS did not have an IPv6 address at the time. The DNS entry AAAA remained. The name resolved to IPv6, but the server did not respond in IPv6. I decided that it would be sufficient to simply ensure that all but SSH, HTTP, and HTTPS were closed via firewalld just before enabling the address.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Automatic DROP based on detection logs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This mechanism sends requests that the WAF has already rejected to firewalld based on their number. It is prone to involving shared IPs and cloud addresses for payment and APIs. Skipping the notification stage and automatically blocking them would have significant side effects given the current volume of requests.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Constantly synchronize attack IP addresses with multiple other VPS servers.<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The same campaign can hit several servers around the same time. Sources are often disposable, and a mistaken drop spreads to every server. It is easier to let SiteGuard BLOCK on each server, and to add by hand only what stands out in that server's log.<\/p>\n\n\n\n<figure class=\"text-figure\"><div class=\"later-note\"><div class=\"later-note__col\"><p class=\"later-note__kicker\">Done for this round<\/p><h3>What went in<\/h3><ul><li>Files that do not need to be made public and unknown hosts have been closed.<\/li><li>I updated the app and made the management screen accessible only through the work network.<\/li><li>I installed fail2ban and the OS security updates.<\/li><li>The admin port, and only the sources that stood out, were dropped as a supplement.<\/li><\/ul><\/div><div class=\"later-note__col\"><p class=\"later-note__kicker\">When a reason appears<\/p><h3>Add it then<\/h3><ul><li>The day to enable IPv6<\/li><li>A day when the same source still surges after it has been blocked<\/li><li>The day when only the production management URL is being attacked repeatedly<\/li><li>A day when the same campaign stands out at once on several other servers<\/li><\/ul><\/div><\/div><figcaption>Some things are meant to be finished this time, while others can wait until a suitable opportunity arises.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Leave it so that it can be restored.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I copied the configuration files I was going to modify, noting the date and time, before starting the work. When updating the application, I left a database dump in a separate directory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The public site will be checked for the following changes each time they are made.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Whether the homepage returns HTTP 200<\/li>\n\n\n\n<li>Certificate issuer and expiration date<\/li>\n\n\n\n<li>Will the app&#039;s management screen only open from authorized connections?<\/li>\n\n\n\n<li>Is the environment variable file still showing 403 or 404?<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">What to watch afterward<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I&#039;ve finished the implementation for now. I&#039;m continuing with the following three things:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If the IP address of your work network changes, update the SiteGuard management port and the permissions for the app&#039;s management screen.<\/li>\n\n\n\n<li>Check SiteGuard&#039;s detections once a week. See if any new types of URLs have been added.<\/li>\n\n\n\n<li>If the production admin URL keeps being targeted, the same IP surges after a DROP, or real harm appears, add something then.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The sources that stood out the first time are included. Everything else is left to the official signature BLOCK. I do not copy busy log lines over by hand each time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Checklist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The steps to take when transferring to another VPS are as follows.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Check that the log you checked is judged as BLOCK.<\/li>\n\n\n\n<li>Stop exposing phpinfo and the standard document root.<\/li>\n\n\n\n<li>The status code confirms that the environment variable file cannot be read from outside.<\/li>\n\n\n\n<li>Delete unused hosts and set unknown hosts to 403 for wildcard access.<\/li>\n\n\n\n<li>Move the app to a security release in its own product line, and reject the unused <code data-no-translation=\"\">xmlrpc.php<\/code>.<\/li>\n\n\n\n<li>Enter the allowed IP addresses in the app&#039;s management screen.<\/li>\n\n\n\n<li><code data-no-translation=\"\">expose_php=Off<\/code> .<\/li>\n\n\n\n<li>Install fail2ban and exclude the work line from being targeted.<\/li>\n\n\n\n<li>The OS will only have automatic security updates, and restarts will remain manual.<\/li>\n\n\n\n<li>Only add the most prominent sources to SiteGuard and firewalld.<\/li>\n\n\n\n<li>SiteGuard&#039;s management ports should be limited to the work network and localhost.<\/li>\n\n\n\n<li>After the changes are reflected, check the response and certificates on the public site.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">It&#039;s impossible to eliminate entry points entirely. New sources, unknown attacks, and changes in operational lines will remain. The benefit of this approach lies in reducing the amount of material available for reconnaissance and unused entry points, and mitigating the impact of any slip-throughs through updates and reduced privileges.<\/p>\n\n\n\n<aside class=\"figure-credit\"><p>Entry points cannot be brought to zero. New sources, unknown attacks, and changes in the work network remain. The effect this time is to reduce reconnaissance material and unused entrances, and to limit the blast radius of anything that gets through by keeping software updated and privileges small. <a href=\"https:\/\/www.flaticon.com\/\" rel=\"noopener\" target=\"_blank\">Flaticon<\/a>. Shield, door, server, DNS, certificate, and brick wall are by <a href=\"https:\/\/www.flaticon.com\/authors\/magnific\" rel=\"noopener\" target=\"_blank\">Magnific<\/a>. Firewall is by <a href=\"https:\/\/www.flaticon.com\/authors\/iconmas\" rel=\"noopener\" target=\"_blank\">iconmas<\/a>. Key is by <a href=\"https:\/\/www.flaticon.com\/authors\/smashicons\" rel=\"noopener\" target=\"_blank\">Smashicons<\/a>. Clock is by <a href=\"https:\/\/www.flaticon.com\/authors\/justicon\" rel=\"noopener\" target=\"_blank\">justicon<\/a>. Document is by <a href=\"https:\/\/www.flaticon.com\/authors\/awicon\" rel=\"noopener\" target=\"_blank\">Awicon<\/a>. Forbidden sign is by <a href=\"https:\/\/www.flaticon.com\/authors\/falcone\" rel=\"noopener\" target=\"_blank\">Falcone<\/a>. Warning is by <a href=\"https:\/\/www.flaticon.com\/authors\/andrean-prabowo\" rel=\"noopener\" target=\"_blank\">Andrean Prabowo<\/a>. Update arrow is by <a href=\"https:\/\/www.flaticon.com\/authors\/laisa-islam-ani\" rel=\"noopener\" target=\"_blank\">Laisa Islam Ani<\/a>\u3002<\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>A record of reading the SiteGuard logs on a Sakura VPS and closing public files, unknown hosts, the admin screen, fail2ban, updates, and the admin port from the outside. Addresses are examples.<\/p>","protected":false},"author":2,"featured_media":2377,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2353","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/posts\/2353","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/comments?post=2353"}],"version-history":[{"count":11,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/posts\/2353\/revisions"}],"predecessor-version":[{"id":2386,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/posts\/2353\/revisions\/2386"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/media\/2377"}],"wp:attachment":[{"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/media?parent=2353"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/categories?post=2353"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.coppe.jp\/en\/wp-json\/wp\/v2\/tags?post=2353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}