{"id":416,"date":"2025-08-27T21:10:27","date_gmt":"2025-08-27T21:10:27","guid":{"rendered":"https:\/\/1v0.net\/blog\/?p=416"},"modified":"2025-08-27T21:10:29","modified_gmt":"2025-08-27T21:10:29","slug":"optimizing-laravel-for-aws-deployment-step-by-step","status":"publish","type":"post","link":"https:\/\/1v0.net\/blog\/optimizing-laravel-for-aws-deployment-step-by-step\/","title":{"rendered":"Optimizing Laravel for AWS Deployment (Step-by-Step)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>Optimizing Laravel for AWS Deployment (Step-by-Step)<\/strong><\/h2>\n\n\n\n<p>AWS gives you flexible building blocks\u2014EC2 for compute, RDS for databases, ElastiCache for Redis, S3 for storage, and CloudFront for global edge caching. In this step-by-step guide, you\u2019ll prepare your Laravel app for production, provision AWS services, configure Nginx + PHP-FPM on EC2, wire up queues with Horizon, store assets on S3, and add a health check endpoint for load balancers. We\u2019ll keep performance and security front-and-center and link to deep dives where relevant.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>1 &#8211; Production Prep: Env &amp; Optimizations<\/strong><\/h2>\n\n\n\n<p>Before deploying, make sure your app boots fast and reads secrets from environment variables. These commands pre-compile configuration\/routes\/views for minimal runtime overhead (see also <a href=\"\/blog\/10-proven-ways-to-optimize-laravel-for-high-traffic\">Article #41<\/a> for the rationale).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># locally or in your build stage<\/span>\nphp artisan key:generate --force\nphp artisan config:cache\nphp artisan route:cache\nphp artisan view:cache\nphp artisan event:cache<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>These commands write optimized PHP arrays to <code>bootstrap\/cache<\/code>, reducing file I\/O and framework bootstrap time in production.<\/p>\n\n\n\n<!-- DomainException(0): Unknown language: \"dotenv\" --># .env.production (example)\nAPP_ENV=production\nAPP_DEBUG=false\nAPP_URL=https:\/\/your-domain.com\n\nLOG_CHANNEL=stack\nLOG_LEVEL=warning\n\n# database via RDS\nDB_CONNECTION=mysql\nDB_HOST=your-rds-endpoint.amazonaws.com\nDB_PORT=3306\nDB_DATABASE=app\nDB_USERNAME=app_user\nDB_PASSWORD=strong-password\n\n# cache\/session via ElastiCache Redis\nCACHE_DRIVER=redis\nSESSION_DRIVER=redis\nREDIS_HOST=your-redis.xxxxxx.use1.cache.amazonaws.com\nREDIS_PORT=6379\n\n# files &#038; assets\nFILESYSTEM_DISK=s3\nAWS_ACCESS_KEY_ID=&#8230;\nAWS_SECRET_ACCESS_KEY=&#8230;\nAWS_DEFAULT_REGION=us-east-1\nAWS_BUCKET=your-bucket\nAWS_USE_PATH_STYLE_ENDPOINT=false\n\n# queues (Redis) + Horizon\nQUEUE_CONNECTION=redis\n\n\n<p>Use a separate <code>.env.production<\/code> with real endpoints. In AWS, prefer Systems Manager Parameter Store or Secrets Manager instead of raw env files for credentials.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2 &#8211; Provision AWS: RDS, ElastiCache, S3, CloudFront<\/strong><\/h2>\n\n\n\n<p>Create an RDS MySQL (or Postgres) instance, an ElastiCache Redis cluster, and an S3 bucket. Optionally add a CloudFront distribution on top of S3 for global asset delivery. Make sure your EC2 security groups allow egress to these services and RDS\/Redis are restricted to your VPC.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># example: upload public build assets to S3 during deploy<\/span>\nphp artisan storage:link   <span class=\"hljs-comment\"># for local; in prod we serve from S3 directly<\/span>\n<span class=\"hljs-comment\"># build your front-end (Vite\/Mix) then<\/span>\naws s3 sync public\/build s3:\/\/your-bucket\/build --delete<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Syncing compiled assets to S3 lets CloudFront cache them globally. Set long cache-control headers for immutable filenames (Vite\u2019s hashed files).<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>3 &#8211; EC2: PHP-FPM + Nginx Configuration<\/strong><\/h2>\n\n\n\n<p>We\u2019ll run Laravel on EC2 behind Nginx with PHP-FPM. This mirrors our Docker\/Nginx setup from <a href=\"\/blog\/laravel-and-docker-setting-up-a-scalable-dev-environment\">Article #46<\/a> but installed on the instance directly.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># on Ubuntu EC2<\/span>\nsudo apt update\nsudo apt install -y nginx php8.3-fpm php8.3-xml php8.3-mbstring php8.3-zip php8.3-mysql php8.3-bcmath php8.3-curl unzip git\nsudo systemctl <span class=\"hljs-built_in\">enable<\/span> php8.3-fpm nginx<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This installs Nginx and PHP 8.3 with common Laravel extensions. Enable services to start on boot so reboots don\u2019t cause downtime.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Nginx\" data-shcb-language-slug=\"nginx\"><span><code class=\"hljs language-nginx\"><span class=\"hljs-comment\"># \/etc\/nginx\/sites-available\/laravel.conf<\/span>\n<span class=\"hljs-section\">server<\/span> {\n    <span class=\"hljs-attribute\">listen<\/span> <span class=\"hljs-number\">80<\/span>;\n    <span class=\"hljs-attribute\">server_name<\/span> your-domain.com;\n    <span class=\"hljs-attribute\">root<\/span> \/var\/www\/current\/public;\n\n    <span class=\"hljs-attribute\">index<\/span> index.php index.html;\n\n    <span class=\"hljs-attribute\">location<\/span> \/ {\n        <span class=\"hljs-attribute\">try_files<\/span> <span class=\"hljs-variable\">$uri<\/span> <span class=\"hljs-variable\">$uri<\/span>\/ \/index.php?<span class=\"hljs-variable\">$query_string<\/span>;\n    }\n\n    <span class=\"hljs-attribute\">location<\/span> <span class=\"hljs-regexp\">~ \\.php$<\/span> {\n        <span class=\"hljs-attribute\">include<\/span> snippets\/fastcgi-php.conf;\n        <span class=\"hljs-attribute\">fastcgi_pass<\/span> unix:\/run\/php\/php8.3-fpm.sock;\n        <span class=\"hljs-attribute\">fastcgi_read_timeout<\/span> <span class=\"hljs-number\">60s<\/span>;\n    }\n\n    <span class=\"hljs-attribute\">location<\/span> <span class=\"hljs-regexp\">~* \\.(jpg|jpeg|png|gif|css|js|ico|woff2?)$<\/span> {\n        <span class=\"hljs-attribute\">expires<\/span> <span class=\"hljs-number\">7d<\/span>;\n        <span class=\"hljs-attribute\">access_log<\/span> <span class=\"hljs-literal\">off<\/span>;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Nginx<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">nginx<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This server block routes requests to Laravel\u2019s <code>index.php<\/code> and serves static files with caching. Point <code>root<\/code> to your release directory (<code>\/var\/www\/current<\/code>) to support zero-downtime symlink deployments.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">sudo ln -s \/etc\/nginx\/sites-available\/laravel.conf \/etc\/nginx\/sites-enabled\/laravel.conf\nsudo nginx -t &amp;&amp; sudo systemctl reload nginx<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Symlink the site, test the config, and reload Nginx without dropping connections. For more Nginx hardening, see <a href=\"\/blog\/laravel-nginx-best-practices-for-production\">Article #56<\/a>.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>4 &#8211; Deploy Script: Zero-Downtime Releases<\/strong><\/h2>\n\n\n\n<p>Use a simple release pattern: upload a timestamped build directory, run composer\/artisan, then atomically switch the <code>current<\/code> symlink.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># \/usr\/local\/bin\/deploy.sh (run as a deploy user)<\/span>\n<span class=\"hljs-built_in\">set<\/span> -euo pipefail\n\nAPP_DIR=\/var\/www\nRELEASES=<span class=\"hljs-variable\">$APP_DIR<\/span>\/releases\nNEW=<span class=\"hljs-variable\">$RELEASES<\/span>\/$(date +%Y%m%d%H%M%S)\n\nmkdir -p <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NEW<\/span>\"<\/span>\n<span class=\"hljs-comment\"># rsync or unzip your build into $NEW<\/span>\nrsync -az --delete build\/ <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NEW<\/span>\/\"<\/span>\n\n<span class=\"hljs-built_in\">cd<\/span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NEW<\/span>\"<\/span>\ncomposer install --no-dev --optimize-autoloader\nphp artisan config:cache\nphp artisan route:cache\nphp artisan view:cache\nphp artisan migrate --force\n\nln -sfn <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NEW<\/span>\"<\/span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$APP_DIR<\/span>\/current\"<\/span>\nsudo systemctl reload php8.3-fpm\nsudo systemctl reload nginx<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This script minimizes downtime by swapping symlinks only after the new release is warmed and migrations are applied. For CI\/CD automation, see <a href=\"\/blog\/cicd-for-laravel-projects-with-github-actions\">Article #54<\/a>.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>5 &#8211; Queues &amp; Horizon on EC2<\/strong><\/h2>\n\n\n\n<p>Use Horizon to manage Redis queues (jobs, notifications, broadcasts). Run it under systemd so it restarts on failure or reboot (see <a href=\"\/blog\/how-to-use-laravel-horizon-for-queue-monitoring\">Article #45<\/a> for UI and scaling).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"TOML, also INI\" data-shcb-language-slug=\"ini\"><span><code class=\"hljs language-ini\"><span class=\"hljs-comment\"># \/etc\/systemd\/system\/horizon.service<\/span>\n<span class=\"hljs-section\">&#91;Unit]<\/span>\n<span class=\"hljs-attr\">Description<\/span>=Laravel Horizon\n<span class=\"hljs-attr\">After<\/span>=network.target\n\n<span class=\"hljs-section\">&#91;Service]<\/span>\n<span class=\"hljs-attr\">User<\/span>=www-data\n<span class=\"hljs-attr\">Type<\/span>=simple\n<span class=\"hljs-attr\">WorkingDirectory<\/span>=\/var\/www\/current\n<span class=\"hljs-attr\">ExecStart<\/span>=\/usr\/bin\/php artisan horizon\n<span class=\"hljs-attr\">Restart<\/span>=always\n<span class=\"hljs-attr\">RestartSec<\/span>=<span class=\"hljs-number\">3<\/span>\n\n<span class=\"hljs-section\">&#91;Install]<\/span>\n<span class=\"hljs-attr\">WantedBy<\/span>=multi-user.target<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TOML, also INI<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">ini<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Enable and start the service so jobs are continuously processed. Horizon also provides a dashboard at <code>\/horizon<\/code> for throughput\/failed job metrics.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">sudo systemctl daemon-reload\nsudo systemctl <span class=\"hljs-built_in\">enable<\/span> --now horizon<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Reload systemd and start Horizon immediately. Pair this with Redis in ElastiCache for a robust, low-latency queue layer (background on queues in <a href=\"\/blog\/how-to-use-laravel-queues-for-faster-performance\">Article #42<\/a>).<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>6 &#8211; Optional: Octane for Concurrency<\/strong><\/h2>\n\n\n\n<p>If your app is CPU-bound and you need higher RPS, consider running <strong>Laravel Octane<\/strong> (Swoole\/RoadRunner) behind Nginx on EC2 (see <a href=\"\/blog\/optimizing-laravel-for-high-concurrency-with-octane\">Article #44<\/a> for benchmarks and configuration).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"TOML, also INI\" data-shcb-language-slug=\"ini\"><span><code class=\"hljs language-ini\"><span class=\"hljs-comment\"># \/etc\/systemd\/system\/octane.service<\/span>\n<span class=\"hljs-section\">&#91;Unit]<\/span>\n<span class=\"hljs-attr\">Description<\/span>=Laravel Octane\n<span class=\"hljs-attr\">After<\/span>=network.target\n\n<span class=\"hljs-section\">&#91;Service]<\/span>\n<span class=\"hljs-attr\">User<\/span>=www-data\n<span class=\"hljs-attr\">WorkingDirectory<\/span>=\/var\/www\/current\n<span class=\"hljs-attr\">ExecStart<\/span>=\/usr\/bin\/php artisan octane:start --server=swoole --port=<span class=\"hljs-number\">9000<\/span> --workers=<span class=\"hljs-number\">8<\/span> --task-workers=<span class=\"hljs-number\">4<\/span>\n<span class=\"hljs-attr\">Restart<\/span>=always\n<span class=\"hljs-attr\">RestartSec<\/span>=<span class=\"hljs-number\">3<\/span>\n\n<span class=\"hljs-section\">&#91;Install]<\/span>\n<span class=\"hljs-attr\">WantedBy<\/span>=multi-user.target<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TOML, also INI<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">ini<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Expose Octane on an internal port and proxy to it from Nginx. Keep <code>max_requests<\/code> set in <code>config\/octane.php<\/code> so workers recycle and memory stays healthy.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>7 &#8211; S3 Filesystem &amp; CloudFront<\/strong><\/h2>\n\n\n\n<p>Move user uploads to S3 for durability and scale, and serve them via CloudFront for low latency worldwide.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ config\/filesystems.php (snippet)<\/span>\n<span class=\"hljs-string\">'disks'<\/span> =&gt; &#91;\n    <span class=\"hljs-string\">'s3'<\/span> =&gt; &#91;\n        <span class=\"hljs-string\">'driver'<\/span> =&gt; <span class=\"hljs-string\">'s3'<\/span>,\n        <span class=\"hljs-string\">'key'<\/span>    =&gt; env(<span class=\"hljs-string\">'AWS_ACCESS_KEY_ID'<\/span>),\n        <span class=\"hljs-string\">'secret'<\/span> =&gt; env(<span class=\"hljs-string\">'AWS_SECRET_ACCESS_KEY'<\/span>),\n        <span class=\"hljs-string\">'region'<\/span> =&gt; env(<span class=\"hljs-string\">'AWS_DEFAULT_REGION'<\/span>, <span class=\"hljs-string\">'us-east-1'<\/span>),\n        <span class=\"hljs-string\">'bucket'<\/span> =&gt; env(<span class=\"hljs-string\">'AWS_BUCKET'<\/span>),\n        <span class=\"hljs-string\">'url'<\/span>    =&gt; env(<span class=\"hljs-string\">'AWS_URL'<\/span>), <span class=\"hljs-comment\">\/\/ set to CloudFront domain for public URLs<\/span>\n        <span class=\"hljs-string\">'visibility'<\/span> =&gt; <span class=\"hljs-string\">'public'<\/span>,\n    ],\n],<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Setting <code>AWS_URL<\/code> to your CloudFront domain ensures generated URLs (e.g., <code>Storage::url()<\/code>) use the CDN, not the S3 endpoint. Cache objects with long TTLs since filenames are versioned.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>8 &#8211; Health Check Endpoint (UI)<\/strong><\/h2>\n\n\n\n<p>Add a simple route for ALB\/ELB health checks that verifies DB\/Redis connectivity without heavy logic.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ routes\/web.php<\/span>\nRoute::get(<span class=\"hljs-string\">'\/health'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">try<\/span> {\n        DB::connection()-&gt;getPdo();\n        Cache::put(<span class=\"hljs-string\">'healthcheck'<\/span>, now(), <span class=\"hljs-number\">5<\/span>);\n        <span class=\"hljs-keyword\">return<\/span> response()-&gt;json(&#91;<span class=\"hljs-string\">'status'<\/span> =&gt; <span class=\"hljs-string\">'ok'<\/span>, <span class=\"hljs-string\">'time'<\/span> =&gt; now()], <span class=\"hljs-number\">200<\/span>);\n    } <span class=\"hljs-keyword\">catch<\/span> (\\Throwable $e) {\n        <span class=\"hljs-keyword\">return<\/span> response()-&gt;json(&#91;<span class=\"hljs-string\">'status'<\/span> =&gt; <span class=\"hljs-string\">'fail'<\/span>], <span class=\"hljs-number\">500<\/span>);\n    }\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Your load balancer can poll <code>\/health<\/code> to remove unhealthy instances automatically. Keep it lightweight and fast.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>9 &#8211; Security Hardening<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Terminate HTTPS at ALB or Nginx using an ACM certificate.<\/li>\n<li>Keep <code>APP_DEBUG=false<\/code> in production; never expose stack traces.<\/li>\n<li>Restrict SSH with key pairs and use SSM Session Manager where possible.<\/li>\n<li>Use Parameter Store\/Secrets Manager for DB\/API keys; rotate regularly.<\/li>\n<li>Enable OPcache and set sane limits (covered in <a href=\"\/blog\/10-proven-ways-to-optimize-laravel-for-high-traffic\">Article #41<\/a>).<\/li>\n<\/ul>\n\n\n\n<p>Security posture improves resilience and compliance. Pair with WAF and security groups that only expose ports 80\/443 to the internet, keeping DB\/Redis private.<\/p>\n\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>You configured a production-grade Laravel stack on AWS: EC2 with Nginx + PHP-FPM, RDS for MySQL, ElastiCache Redis for cache\/sessions\/queues, S3 + CloudFront for assets, and a health check endpoint for load balancers. With zero-downtime deploys, Horizon for queues, and optional Octane for high concurrency, your app is ready to scale reliably and securely.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\">What\u2019s Next<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/blog\/cicd-for-laravel-projects-with-github-actions\">CI\/CD for Laravel Projects with GitHub Actions<\/a> \u2014 automate your zero-downtime deployment pipeline.<\/li>\n<li><a href=\"\/blog\/laravel-nginx-best-practices-for-production\">Laravel &amp; Nginx: Best Practices for Production<\/a> \u2014 tune Nginx timeouts, compression, and buffering for EC2.<\/li>\n<li><a href=\"\/blog\/laravel-deployment-checklist-for-2025\">Laravel Deployment Checklist for 2025<\/a> \u2014 a concise pre-launch audit you can run for every release.<\/li>\n<\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>Optimizing Laravel for AWS Deployment (Step-by-Step) AWS gives you flexible building blocks\u2014EC2 for compute, RDS for databases, ElastiCache for Redis, S3 for storage, and CloudFront for global edge caching. In this step-by-step guide, you\u2019ll prepare your Laravel app for production, provision AWS services, configure Nginx + PHP-FPM on EC2, wire up queues with Horizon, store [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":420,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[75,74,71],"class_list":["post-416","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","tag-aws","tag-deployment","tag-devops"],"_links":{"self":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/416","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/comments?post=416"}],"version-history":[{"count":1,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/416\/revisions"}],"predecessor-version":[{"id":419,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/416\/revisions\/419"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media\/420"}],"wp:attachment":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media?parent=416"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/categories?post=416"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/tags?post=416"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}