-
By Ros socheath
-
Sep 25, 2025
- Deployment
-
6 min read
How to Deploy a Laravel Application to Production with Docker and Nginx Reverse Proxy
Here's a complete guide for deploying a Laravel application to production using Docker and Nginx with SSL. This is based on my recent deployment experience that I'd like to share with everyone.
Prerequisites
- Basic knowledge of Docker, Laravel, and Nginx
- A server or hosting provider that supports Docker
- Your Laravel application code
- Domain name (optional but recommended)
Project Overview
This deployment setup includes:
- Laravel application
- PHP 8.3 with FPM
- Nginx as a web server with reverse proxy
- SSL configuration for secure HTTPS connections
- Docker containerization for consistent deployment
Step 1: Create Your Dockerfile
The Dockerfile is the foundation of your deployment:
Create Dockerfile in to you project file
FROM ubuntu:latest
# Update and set timezone
RUN apt update && apt upgrade -y
ENV TZ=Asia/Phnom_Penh
RUN apt-get update && \
apt-get install -y tzdata && \
ln -fs /usr/share/zoneinfo/Asia/Phnom_Penh /etc/localtime && \
dpkg-reconfigure -f noninteractive tzdata
# Install dependencies
RUN apt install -y libonig-dev libxml2-dev imagemagick nano
RUN apt-get update && apt-get install -y --no-install-recommends --quiet \
git \
libzip-dev \
zip \
curl \
sudo \
unzip \
ffmpeg \
# Additional dependencies for image processing
libxpm-dev \
libwebp-dev \
libgd-dev \
zlib1g-dev \
libbz2-dev \
libpng-dev \
libjpeg-dev \
libicu-dev \
libmcrypt-dev \
build-essential \
libreadline-dev \
libfreetype6-dev \
libmagickwand-dev \
libjpeg-turbo8-dev \
g++
# Install Nginx
RUN apt install -y nginx
# Install PHP 8.3 and extensions
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \
php8.3-fpm \
php8.3-mysql \
php8.3-imagick \
php8.3-bcmath \
php8.3-ctype \
php8.3-fileinfo \
php8.3-mbstring \
php8.3-pdo \
php8.3-tokenizer \
php8.3-curl \
php8.3-zip \
php8.3-gd \
php8.3-xml \
php8.3-bz2 \
composer \
&& rm -rf /var/lib/apt/lists/*
# Configure PHP for production use
RUN sed -i "s/^max_execution_time\s*=.*/max_execution_time = 600/" /etc/php/8.3/fpm/php.ini \
&& sed -i "s/^max_input_time\s*=.*/max_input_time = 600/" /etc/php/8.3/fpm/php.ini \
&& sed -i "s/^memory_limit\s*=.*/memory_limit = 1024M/" /etc/php/8.3/fpm/php.ini \
&& sed -i 's/upload_max_filesize\s*=.*/upload_max_filesize = 512M/' /etc/php/8.3/fpm/php.ini \
&& sed -i 's/post_max_size\s*=.*/post_max_size = 512M/' /etc/php/8.3/fpm/php.ini
# Install Node.js and npm for frontend assets
RUN apt-get update && apt-get install -y nodejs npm && rm -rf /var/lib/apt/lists/*
# Generate self-signed SSL certificate
RUN apt-get update && apt-get install -y openssl && rm -rf /var/lib/apt/lists/* && \
mkdir -p /ssl && \
openssl genrsa -out /ssl/localhost.key 2048 && \
openssl req -new -key /ssl/localhost.key -out /ssl/localhost.csr -subj "/C=US/ST=State/L=City/O=Organization/OU=Department/CN=localhost" && \
openssl x509 -req -days 365 -in /ssl/localhost.csr -signkey /ssl/localhost.key -out /ssl/localhost.crt
# Copy application code and set up Laravel
WORKDIR /ssl
COPY . /project_file_name
WORKDIR /project_file_name
COPY .env.production .env # can use another env
# Install dependencies and build assets
RUN composer install --no-dev --optimize-autoloader
RUN php artisan key:generate
RUN npm install
RUN npm run build
# Configure Nginx
COPY localhost.conf /etc/nginx/sites-available/localhost.conf
RUN ln -s /etc/nginx/sites-available/localhost.conf /etc/nginx/sites-enabled && \
rm /etc/nginx/sites-enabled/default
# Forward Nginx logs to Docker logs
RUN ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log
# Set correct permissions
RUN chown -R www-data:www-data /project_file_name && \
chmod -R 775 /project_file_name/storage /project_file_name/bootstrap/cache
# Optimize Laravel for production
RUN php artisan optimize
RUN php artisan config:cache
RUN php artisan route:cache
RUN php artisan view:cache
RUN php artisan event:cache
RUN php artisan cache:clear
EXPOSE 8000
# Start PHP-FPM and Nginx
CMD service php8.3-fpm start && nginx -g 'daemon off;'replace project_file_name with your name file part
Step 2: Configure Nginx
Local Server Configuration
Create a localhost.conf file in your project:
server {
listen 8000 ssl;
server_name localhost;
root /project_file_name/public;
index index.php index.html;
# SSL Certificate
ssl_certificate /ssl/localhost.crt;
ssl_certificate_key /ssl/localhost.key;
# Increase max upload file size
client_max_body_size 512M;
# Default location
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Error handling
error_page 404 /index.php;
# PHP-FPM configuration
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
# Timeout settings for PHP-FPM
fastcgi_connect_timeout 600s;
fastcgi_send_timeout 600s;
fastcgi_read_timeout 600s;
}
# Security configurations
location ~ /\.(?!well-known).* {
deny all;
access_log off;
log_not_found off;
}
# Protect sensitive directories
location ~* /(storage|.env) {
deny all;
}
# Optimize static files handling
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|otf|eot|ttc|mp4|webm|ogg|ogv|htm|html|txt|xml|json)$ {
expires max;
log_not_found off;
access_log off;
}
}replace project_file_name with your name file part
create a localhost_reverse.conf file in to your project file:
server {
server_name you_domain_name or IP; # Replace with your domain
# Limit the size of client requests
client_max_body_size 512M;
# Gzip Compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml+rss text/javascript image/svg+xml;
gzip_min_length 256;
gzip_comp_level 5;
gzip_vary on;
gzip_disable "msie6";
# Timeout settings
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
client_body_timeout 600s;
client_header_timeout 600s;
# Proxy to the Docker container
location / {
proxy_pass https://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
}
# Logs
access_log /var/log/nginx/project_file_name_access.log;
error_log /var/log/nginx/project_file_name_error.log;
listen 80;
}replace project_file_name with your name file part
Step 3: Prepare Your Laravel Application
- Prepare your production environment file:
- Create a .env.prodution file based on your .env.example
- Configure database credentials, app URL, etc. for production
- Make sure your Laravel application is ready for production:
- Test all functionality locally
- Ensure all migrations work correctly
Step 4: Building and Deploying
- Build your Docker image:
docker build -t my-laravel-app .
- Run your Docker container:
docker run -p 8000:8000 \ --name=my-laravel-app \ --restart=always \ -d my-laravel-app
- reverse proxy configuration, place it on your host machine's Nginx configuration directory and restart Nginx:
sudo cp localhost_reverse.conf /etc/nginx/sites-available/you-domain-name sudo ln -s /etc/nginx/sites-available/you-domain-name /etc/nginx/sites-enabled sudo nginx -t sudo systemctl restart nginx
Step 5: Post-Deployment Tasks
- Set up a proper SSL certificate (recommended for production):
- Use Let's Encrypt for free SSL certificates
- Replace the self-signed certificates in the Docker container
- Configure backups for your database and uploaded files
- Set up monitoring for your application
Security Considerations
- The configurations include several security practices:
- Hidden files protection
- Protection of sensitive directories like storage and .env files
- SSL implementation
- Properly configured file permissions
- Consider adding:
- Rate limiting for API endpoints
- Web Application Firewall (WAF)
- Regular security audits
Conclusion
This deployment setup provides a production-ready environment for your Laravel application. The Docker containerization ensures consistent deployment across different environments.
Happy deploying!