Laravel Production Deployment Security Checklist

A comprehensive security checklist for deploying Laravel applications to production. Covers environment config, server hardening, access control, and monitoring.

Progress
0 / 20 completed

Environment & Configuration

Set APP_DEBUG=false in production

Debug mode exposes full stack traces, environment variables, and database credentials in error pages. This is the single most common Laravel security misconfiguration in production.

Set APP_ENV=production

Setting the environment to production ensures Laravel uses production-appropriate error handling, caching, and logging. Some packages also change behavior based on this value.

Generate a unique APP_KEY

The APP_KEY is used to encrypt session data, cookies, and other sensitive values. Never reuse the key from development or share it between environments. Run php artisan key:generate to create a new one.

Verify .env file is not publicly accessible

Your .env file contains database credentials, API keys, and the APP_KEY. Ensure your web server does not serve this file by testing the URL directly: yourapp.com/.env should return a 404.

Configure proper logging (stack or daily, not single)

Use the daily or stack log channel in production. The single channel creates one massive log file that is hard to manage. Ensure logs do not contain sensitive user data.

Server & Infrastructure

Enforce HTTPS with a valid SSL certificate

All production traffic must use HTTPS. Obtain a certificate from Let's Encrypt or your provider, and ensure it covers all subdomains. Set URL::forceScheme('https') in AppServiceProvider.

Set up the HSTS header

Add the Strict-Transport-Security header to tell browsers to always use HTTPS. Use a long max-age (31536000 seconds = 1 year) and include includeSubDomains if applicable.

Close unnecessary ports (database, Redis, memcached)

Database ports (3306, 5432), Redis (6379), and memcached (11211) should not be accessible from the public internet. Use firewall rules to restrict access to your application server only.

Set proper file permissions on storage and bootstrap/cache

The storage and bootstrap/cache directories need to be writable by the web server but should not be world-writable. Use 775 with the correct group ownership.

Disable directory listing on the web server

Directory listing allows anyone to browse your file structure. Disable it in your Nginx or Apache configuration to prevent information leakage.

Access Control & Authentication

Disable or restrict Telescope in production

Telescope records requests, queries, exceptions, and more. In production, either disable it entirely or restrict access with the gate() method in TelescopeServiceProvider to admin users only.

Restrict Horizon dashboard access

Horizon's dashboard shows job details and Redis information. Use the gate() method in HorizonServiceProvider to restrict access to authorized users only.

Remove or protect default routes (e.g., /api/user)

Laravel ships with a default /api/user route. Remove it if unused, or ensure it requires authentication. Review routes/api.php and routes/web.php for any unnecessary endpoints.

Ensure password reset tokens expire appropriately

Check config/auth.php for the passwords.users.expire value. The default is 60 minutes, which is reasonable. Shorter values (15-30 minutes) are more secure for sensitive applications.

Enable rate limiting on login and registration routes

Apply the throttle middleware to authentication routes to prevent brute-force attacks. Laravel Breeze and Fortify include this by default, but verify it is active.

Security Headers & Monitoring

Add Content-Security-Policy header

CSP prevents XSS attacks by specifying which sources of content are allowed. Start with a restrictive policy and loosen it as needed. At minimum, set default-src 'self'.

Add X-Frame-Options header (DENY or SAMEORIGIN)

This header prevents clickjacking attacks by controlling whether your site can be embedded in iframes. Set it to DENY unless you specifically need iframe embedding.

Add X-Content-Type-Options: nosniff header

Prevents browsers from MIME-type sniffing, which can lead to security vulnerabilities when the browser interprets files differently than intended.

Add Referrer-Policy header

Controls how much referrer information is sent with requests. Set to strict-origin-when-cross-origin or no-referrer to prevent leaking URLs to third parties.

Set up continuous external monitoring

Use a tool like StackShield to continuously monitor your application's external security posture. Deployments, server updates, and configuration changes can silently introduce vulnerabilities.

Frequently Asked Questions

What is the most critical security step when deploying Laravel to production?

Setting APP_DEBUG=false is the single most critical step. Debug mode exposes your environment variables (including database credentials and API keys), full stack traces, and application internals to anyone who triggers an error.

How do I check if my .env file is exposed?

Visit your-domain.com/.env in a browser. If you see your environment variables, it is exposed. This is a critical vulnerability. Configure your web server to block access to dotfiles.

Should I use Telescope in production?

Telescope can be useful in production for debugging, but it must be restricted to authorized users only. Use the gate() method in TelescopeServiceProvider and consider using Telescope::filter() to limit what is recorded.

Related Fix Guides

Other Checklists

Automate These Checks with StackShield

Stop running through checklists manually. StackShield continuously monitors your Laravel application for the security issues that matter most.

Start Free Trial