Dockerize HelloWorld Laravel App to deploy on Render

This is a clean Laravel + Docker + Nginx example for Render deployment (Render has a few special requirements like no docker-compose and starting services in a single container)
Here’s a step-by-step plan:
- Create a blank Laravel app to get started
composer create-project laravel/laravel helloworldapp
cd helloworldapp
Define a simple route
Open the file:
routes/web.php
Replace all content with just:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return 'Hello, World!';
});
✅ Now when you visit /, it will directly show “Hello, World!” in plain text.
- Create the Folder Structure
Inside your Laravel app:
mkdir -p docker/nginx
Then create these 2 files:
(a) Dockerfile (at root)
# Use PHP-FPM image
FROM php:8.2-fpm
# Install system dependencies
RUN apt-get update && apt-get install -y \
nginx \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip unzip \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Install Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html
# Copy app files
COPY . .
# Copy Nginx config
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
# Set permissions
RUN chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
# Expose HTTP port
EXPOSE 80
# Start Nginx and PHP-FPM together
CMD service nginx start && php-fpm
(b) docker/nginx/nginx.conf
worker_processes 1;
events { worker_connections 1024; }
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
}
}
- .env Changes
Make sure your .env production values are set like:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourapp.onrender.com
# Database can be left empty for now if no db
DB_CONNECTION=mysql
DB_HOST=your-db-host
DB_PORT=3306
DB_DATABASE=your-db-name
DB_USERNAME=your-db-user
DB_PASSWORD=your-db-password
If you don’t want database for now (just Hello World), it’s fine.
- Push Code to GitHub
git init
git add .
git commit -m "Initial blank Laravel app with Docker for Render"
git branch -M main
git remote add origin https://github.com/yourusername/helloworldapp.git
git push -u origin main
- Create a Service on Render
On Render Dashboard:
• Create a New Web Service.
• Connect your GitHub repo.
• Environment: Docker
• Root Directory: (leave empty unless Dockerfile is inside a subfolder)
• Build Command: (leave blank)
• Start Command: (leave blank)
That’s it!
- Final Structure
helloworldapp/
├── app/
├── bootstrap/
├── config/
├── docker/
│ └── nginx/
│ └── nginx.conf
├── public/
├── routes/
├── storage/
├── Dockerfile
├── .env
└── ...
✅ This will correctly run a Laravel blank app using Docker and Nginx on Render!
✅ No MySQL inside container (use external if needed).
✅ Fast and clean deployment.
Expected Errors and Fixes:
Enable Laravel error logs
Inside your .env/ environment variables on render, make sure:
APP_DEBUG=true
Set APP_DEBUG=true temporarily to see actual error message on web browser.
(Make sure to turn it back to false in production after debugging.)
Error 1:
Warning: require(/var/www/html/public/../vendor/autoload.php): Failed to open stream: No such file or directory
Fatal error: Uncaught Error: Failed opening required '/var/www/html/public/../vendor/autoload.php'
→ Your Laravel app inside the container does not have the /vendor folder (which contains all Laravel’s dependencies).
→ Composer install was not run inside the Docker build.
Here’s how to fix it:
We need to add composer install inside the Dockerfile after copying the Laravel code.
Update Dockerfile like this:
# Use PHP-FPM image
FROM php:8.2-fpm
# Install system dependencies
RUN apt-get update && apt-get install -y \
nginx \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip unzip \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Install Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html
# Copy app files
COPY . .
# Install Laravel dependencies
RUN composer install --no-dev --optimize-autoloader
# Copy Nginx config
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
# Set permissions
RUN chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
# Expose HTTP port
EXPOSE 80
# Start Nginx and PHP-FPM together
CMD service nginx start && php-fpm
✅ This new line:
RUN composer install --no-dev --optimize-autoloader
automatically generates the /vendor folder inside the container during build!
Error 2:
file_put_contents(/var/www/html/storage/framework/views/bae129cef9e600352d1c88ca55b5c61c.php): Failed to open stream: Permission denied
→ Laravel cannot write into the storage/ folder inside your container.
Why?
Because folder permissions are too strict — PHP does not have permission to create cache files inside storage/framework/views.
You must set correct permissions on these folders inside the Dockerfile!
Add the two lines to your Dockerfile after copying files and running composer install:
# Copy app files
COPY . .
# Install Laravel dependencies
RUN composer install --no-dev --optimize-autoloader
# Set correct permissions
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
RUN chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache
# Copy Nginx config
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
✅ These two lines:
• Give ownership to www-data (which PHP uses)
• Allow read-write-execute permissions correctly (775)
Error 3:
No application encryption key has been specified.
Laravel needs an APP_KEY (an encryption key) to function — it’s missing in your .env file.
Laravel uses this APP_KEY to encrypt cookies, sessions, and other sensitive data.
Fix:
Step 1 — Locally, generate a key
On your computer (in the Laravel project root), run:
php artisan key:generate --show
Example output:
base64:5t7xkqf++somethingrandom==
Step 2 — Add it to your .env
In your project .env file, add:
APP_KEY=base64:5t7xkqf++somethingrandom==
(if APP_KEY already exists but is empty, just replace it.)
Step 3 — Push changes
git add .env
git commit -m "Added APP_KEY"
git push
(If you don’t want to push .env publicly, another way is to set the environment variable on Render dashboard — I’ll show you below.)
Alternative (Best Practice for Production):
Instead of pushing .env to GitHub, you can set APP_KEY in Render settings:
1. Go to Render Dashboard → Your Service → Environment → Environment Variables
2. Add:
Key:Value APP_KEY: base64:5t7xkqf++somethingrandom==
(Use the key you generated on local.)
Error 4:
Database file at path [/var/www/html/database/database.sqlite] does not exist.
Ensure this is an absolute path to the database.
(Connection: sqlite, SQL: select * from "sessions" where "id" = flilh0FuGJvYDPTYs7MqrlSfHiVS2QWjAXkSU1pA limit 1)
Your Laravel .env file (or default config) is trying to connect to SQLite like this:
DB_CONNECTION=sqlite
But there’s no SQLite file (database/database.sqlite) inside your app.
Laravel expects the file to exist when using SQLite. If you don’t want any database for now, you can also comment out or disable all database code and set sessions to file instead of database
Here’s how to add .env variables on Render:
1. Go to your Render Dashboard
2. Click your Web Service (example: helloworldapp-r00k)
3. On the left side, click Environment tab
4. Under Environment Variables, click Add Environment Variable
SESSION_DRIVER = file
git add ., git commit, git push and trigger redeploy on Render.
The Hello World shows up finally!!
Subscribe to my newsletter
Read articles from Sahitya Raj A directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
