Dockerize HelloWorld Laravel App to deploy on Render

Sahitya Raj ASahitya Raj A
6 min read

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:

  1. 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.

  1. 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;
        }
    }
}
  1. .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.

  1. 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
  1. 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!

  1. 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!!

0
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

Sahitya Raj A
Sahitya Raj A