If you want to mitigate DDoS attacks in this day and age, CloudFlare is pretty much the only answer. That, and large CDNs around the world operated by the likes of Google and Amazon, but I’m no enterprise entity and can’t pay thousands of dollars every month just to show my blog posts on the Internet, so CloudFlare it is.

Step 1 – Sign into CloudFlare. Go inside the DNS tab. Set the apex to your server IP, and make sure the cloud icon is orange (that means it is being proxied). For any other subdomains, just set it as CNAME type and point it towards your apex. Why? In the future, if you ever change servers, you only need to update one endpoint (and if you ever need to point your subdomain to a different server, it’s just one configuration to update).

Remember, now that your IP has been proxied, you cannot SSH using your domain anymore, since it is masked with CloudFlare’s CDN IP address (this is a good thing!) Instead, use the actual IP to log in.

Step 2 – Add the nginx configuration below (modifying it to fit your use-case):

server {
    listen 80;
    root /var/www/ideaman924.com;
    index index.php index.html index.htm;

    server_name ideaman924.com www.ideaman924.com;

    location / {
        # try_files $uri $uri/ =404;
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Turn off static file logging
    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
    }

    # Allow for bigger uploads
    client_max_body_size 50M;

}

The above is for the WordPress installation you’re reading from that used to host this blog post. Don’t worry about the listen 80 directive, as certbot will change it anyway.

Some more fancy config (in case I need it in the future when my server has been destroyed):

server {
    listen 80;
    server_name downloads.ideaman924.com;
    root /var/www/downloads.ideaman924.com;

    location / {
        index /_h5ai/public/index.php;
    }


    location /_h5ai/ {
        location ~ \.php$ {
            include fastcgi_params;
            fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
            fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
        }
    }

    # try_files $uri $uri/ =404;

    access_log  /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

}
server {
    listen 80;
    server_name youtube.ideaman924.com;
    return 301 https://www.youtube.com/channel/UCawSYWa8RnTvVilmWnN28uA$request_uri;
}
server {
    listen 80;
    server_name twitter.ideaman924.com;
    return 301 https://twitter.com/ideaman924$request_uri;
}
server {
    listen 80;
    server_name facebook.ideaman924.com;
    return 301 https://facebook.com/ideamaneric$request_uri;
}
server {
    listen 80;
    server_name instagram.ideaman924.com;
    return 301 https://instagram.com/ideamaneric$request_uri;
}
server {
    listen 80;
    server_name linkedin.ideaman924.com;
    return 301 https://www.linkedin.com/in/ideaman924$request_uri;
}
server {
    listen 80;
    server_name telegram.ideaman924.com;
    return 301 https://t.me/ideaman924$request_uri;
}

Now, symlink the configuration:

sudo ln -s /etc/nginx/sites-available/example.ideaman924.com /etc/nginx/sites-enabled/example.ideaman924.com

Step 3 – Install certbot and the CloudFlare DNS plugin.

After installing Certbot runs something like this:

certbot --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/cloudflare.ini -d ideaman924.com -d *.ideaman924.com -i nginx

Remember you need the secrets file set up. Refer to the documentation. Actually, I need that too in the future so I’ll just post it here:

# CloudFlare API credentials used by Certbot
dns_cloudflare_email = john.appleseed@gmail.com
dns_cloudflare_api_key = test_api_key_12345

Now everything should be working correctly!