Nginx Configuration for old Forge servers
Published on by James Brooks
Caleb Porzio recently tweeted, asking for assistance in mitigating an attack he was seeing on the Laravel Livewire documentation site. You can find that tweet here.
Looking at Caleb's server, I noticed a couple of outdated elements in the Nginx configuration. Since Caleb uses Laravel Forge, I realized that the server wasn't utilizing the latest configuration changes we made for handling requests to unconfigured sites. Because of this, it was possible for someone to point their own domain at his server’s IP and make requests to it. Each time a request was made, a new log entry was made because Nginx was unable to find the configured site. We addressed this issue by changing how Forge provisions servers so that all unknown sites are immediately dropped, without logging anything.
Note: Servers provisioned with Laravel Forge after May 2020 will automatically have these settings configured.
Since we're dealing with Nginx, it's essential to SSH into your server and use sudo
to access the root
user. Be careful when implementing these changes, as incorrect alterations could potentially lead to unexpected downtime.
Delete your “default” site
If you're not actively using it, consider removing your server's "default" site. Forge provisions this on your server, allowing quick access to your project without the need for a domain name. However, once your site is configured with a domain, it's advisable to delete the "default" site to prevent responses to your server's IP address.
Create a new catch-all certificate
The initial step in implementing these changes is to create a catch-all
certificate. This certificate will be utilized in the following step.
mkdir -p /etc/nginx/ssl/cat > /etc/nginx/ssl/catch-all.invalid.crt << EOF-----BEGIN CERTIFICATE-----MIIC1TCCAb2gAwIBAgIJAOzFtsytI2mWMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTAeFw0yMTA1MDMxNTU4MTVaFw0zMTA1MDExNTU4MTVaMBoxGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqkjykou8/yD6rUuz91ZvKC0b7HOZrGmZoenZD1qI85fHg1v7aavJPaXvhXHstUq6Vu6oTR/XDLhqKAOUfiRMFF7i2al8cB0VOmNtH8IGfhc5EGZO2uvQRwPUhipdkJWGFDPlME8fNsnCJcUKebaiwYlen00GEgwKUTNrYNLcBNPOTLm9FdiEtTmSIbm7DmVFEVqF1zD/mOzEvU9exeZM8bn0GYAu+/qEUBDYtNWnnreQQIhjH1CBagvZn+JRpfNydASIMbu7oMVR7GiooR5KwqJBCqRMSHJEMeMIksP04GmyMQG0lSS3bnXxm2pVnFW8Xstu7q+4RkPyNP8tS77TECAwEAAaMeMBwwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQA8veEEhCEjevVUpfuh74SgmAWfBQNjSnwqPm20NnRiT3Khp7avvOOgapep31CdGI4cd12PFrqCwh9ov/Y28Cw191usUbLSoYvIs2VUrv8jNXh/V20s6rKICz292FMmNvKtBVf3dGz6dYmbW9J9H44AH/q/y3ljQgCmxFJgAAvAAiKgD9Bf5Y8GvFP7EFyqWOwWTwls91QLlDDbKOegoD1KRRpFZV8qVhMx6lzyAqzK0U9GZGCANv6II5zEgDDXGKt1OVL+90riKuGJW+cmqv00F+/bgvNNhIu2tZt/wN3oPEJVjEj0Z5d8+gvo0NHwlwGYrgjHlSpV2G5KyvZe5dES-----END CERTIFICATE-----EOFcat > /etc/nginx/ssl/catch-all.invalid.key << EOF-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEAuqSPKSi7z/IPqtS7P3Vm8oLRvsc5msaZmh6dkPWojzl8eDW/tpq8k9pe+Fcey1SrpW7qhNH9cMuGooA5R+JEwUXuLZqXxwHRU6Y20fwgZ+FzkQZk7a69BHA9SGKl2QlYYUM+UwTx82ycIlxQp5tqLBiV6fTQYSDApRM2tg0twE085Mub0V2IS1OZIhubsOZUURWoXXMP+Y7MS9T17F5kzxufQZgC77+oRQENi01aeet5BAiGMfUIFqC9mf4lGl83J0BIgxu7ugxVHsaKihHkrCokEKpExIckQx4wiSw/TgabIxAbSVJLdudfGbalWcVbxey27ur7hGQ/I0/y1LvtMQIDAQABAoIBAQCoJUycRgg9pNOckZ5H41rlrBmOCCnLWJRVFrPZPpemwKF0IugeeHTftuHMVaB2ikdA+RXqpsvu7EzU5TO1oRFUFc4n45hNP0P4WkwVDVGchK36v4n532yGLR/osIa9av/mUBA79r6LERPwmL5I4WjbZSLZ7SY1+q3TieXGSUUocmHGzgtSQ5lIKGC6ppE/3GBqoSJB24sEhpqpqnRs3mPe8q6ZhZLAqoEWni/4XrDycVE/BTgVb3qbZe+/4orPvSxLXEQIdvuxI4MhMqKZHeS2DSAQd845YgiR2MjlgjPJU7LaIQSjWkfgDIw9iHIbUcaLYEcMtfCu+xPEd9eZNJQBAoGBAO6RbNavi1w/VjNsmgiFmXIAz5cn1bxkLWpoCq1oXN9uRMKPvBcGxuKdAVVewvXVD9WEM1CSKeqWSH3mcxxqHaOyqy0aZrk98pphMSvo9QCaoaZP+68HNQ1g/Ws82HUS7bVPULgMHFkLu1t1DcfYADjvVrgYuTrrL9yBeyj3b1ORAoGBAMhH1mWaMK3hySMhlfQ7DMfrwsou4tgvALrnkyxyr1FgXCZGJ5ckaVVBmwLns3c5A6+1MDlMVoXWKI7DSjEh7RPxa02QQTS2FWR0ARvf/Wm8WdGyh7k+0L/y+K+66fZjwLsaGjiq7BnvQAt5NgJI9i8wxxWqTVcGKHeM7No7dO+hAoGAalDYphv5CRUYvzYItv+C0HFYEc6oy5oBO0g+aeT2boPflK0lb0WP4HGDpJ3kWFWpBsgxbhiVIXvztle6uND5gHghHKqFWMwoj2/8z8qzVJ+Upl9ClE+r7thoVx/4fsP+tywvlrWe9Hfr+OgDSioSf0z54nTyJzWkUKpLTohmTmECgYASIAY0HbcoFVXpmwGCH9HxSdHQEFwxKlfLkmeMTzi0iZ7tS84LbJ0nvQ81PRjNwlgmD6S0msb9x7rV6LCPL73P3zpRw6tTBON8us7a4fOCHSyXwKttxVSI+oktBiJkTPTFOgCDflxtoGxQXYDYxheZf7WUrVvgc0s4PoW03kqf4QKBgQCvFTk0uBaZ9Aqslty0cPA2LoVclmQZenbxPSRosEYVQJ6urEpoolssW2v3zRTw+Pv3bXxS2F6z6C5whOeaq2V8epF4LyXDBZhiF+ayxUgA/hJAZqoeSrMBziOvF1n30W8rVLx3HjfpA5eV2BbT/4NChXwlPTbCd9xy11GimqPsNQ==-----END RSA PRIVATE KEY-----EOF
Create a new catch-all site
Previously, Forge would configure a /etc/nginx/sites-available/catch-all
site. This has been updated to 000-catch-all
to ensure higher priority when Nginx searches for a site to communicate with.
The site's configuration has also been enhanced to:
- Return a special
444
Nginx code, signaling an immediate connection drop. - Utilize the certificate we just created for all HTTPS requests.
cat > /etc/nginx/sites-available/000-catch-all << EOFserver { listen 80 default_server; listen [::]:80 default_server; listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; server_name _; server_tokens off; ssl_certificate /etc/nginx/ssl/catch-all.invalid.crt; ssl_certificate_key /etc/nginx/ssl/catch-all.invalid.key; ssl_protocols TLSv1.2; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_dhparam /etc/nginx/dhparams.pem; # You can uncomment this if Nginx is v1.19.4 or later # ssl_reject_handshake on; return 444;}EOF # Symlink this into the server.ln -s /etc/nginx/sites-available/000-catch-all /etc/nginx/sites-enabled/000-catch-all
Delete the old catch-all site
With the new catch-all site now set up, it's time to remove the previous one:
rm -rf /etc/nginx/sites-available/catch-allrm -rf /etc/nginx/sites-enabled/catch-all
Test and implement our changes
Before we reload Nginx with our changes, we need to test them to make sure that we’ve not made any mistakes. We can do this by simply running nginx -t
on the server. Nginx will then test the configuration and ensure everything is valid, saving us from any accidental downtime.
Once we’re happy that our configuration is valid, we can now tell Nginx to reload with the latest changes:
service nginx reload
Voila!
Software Developer at Laravel. Checkmango – full-stack A/B testing. Cachet, open-source status pages. Also, the Laravel Artisan cheatsheet and my blog.