Deploy Laravel on Bahriya
Laravel is a full-featured PHP web framework. To run it as a container you need a PHP runtime serving the application over HTTP on a known port. This guide uses an image that runs PHP-FPM behind nginx, listening on port 8080, and deploys it as an HTTP container.
Laravel is a full-featured PHP web framework. To run it as a container you need a PHP runtime serving the application over HTTP on a known port. This guide uses an image that runs PHP-FPM behind nginx, listening on port 8080, and deploys it as an HTTP container.
Only two things change between stacks on Bahriya: the Dockerfile that builds your image, and the port your application listens on. For the setup below, that port is 8080.
Dockerfile
This installs Composer dependencies, sets up PHP-FPM and nginx, and serves the application on port 8080. It uses a lightweight process manager to run both PHP-FPM and nginx in the foreground.
FROM php:8.3-fpm-alpine
# System packages and PHP extensions Laravel commonly needs
RUN apk add --no-cache nginx supervisor \
&& docker-php-ext-install pdo pdo_mysql bcmath
# Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
# Install dependencies first for better build caching
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
# Copy the application and finish the autoloader
COPY . .
RUN composer dump-autoload --optimize \
&& chown -R www-data:www-data storage bootstrap/cache
# nginx listens on 8080 and forwards PHP to FPM; supervisor runs both
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/supervisord.conf /etc/supervisord.conf
EXPOSE 8080
CMD ["supervisord", "-c", "/etc/supervisord.conf"]Configure your nginx server block to listen 8080; with a root of /var/www/html/public, forwarding .php requests to PHP-FPM on 127.0.0.1:9000. Point the health check at a route your app answers with a 2xx.
An alternative for simple deployments is a single-command image that runs php artisan serve --host=0.0.0.0 --port=8080, though the FPM-plus-nginx setup is the more robust production choice.
Application settings
APP_KEY— Laravel needs an application key for encryption and signed cookies. Generate one withphp artisan key:generate --showand supply it as a secret rather than committing it.APP_ENV/APP_DEBUG— setAPP_ENV=productionandAPP_DEBUG=falsein production.- Config and route caching — for a faster boot, run
php artisan config:cacheandphp artisan route:cacheas part of your build. Only cache config once your environment values are available at build time; otherwise cache them at container start instead. - Storage — Laravel writes to
storage/for logs, sessions, and cached views. Ensure it is writable (the Dockerfile above sets ownership). For a filesystem that must survive restarts, attach a persistent volume; see persistent storage.
The .env and secrets
Laravel reads configuration from environment variables (the .env file locally). On Bahriya you do not ship a .env file — you supply the same keys as environment variables and secrets:
- Non-sensitive keys such as
APP_ENV,APP_URL, andLOG_CHANNELas plain environment variables. - Sensitive keys such as
APP_KEY,DB_PASSWORD, and third-party API keys as secrets, encrypted at rest and injected at runtime.
Deploy with the Reis CLI
reis container:create \
--type http \
--name "Laravel App" \
--handle laravel-app \
--image ghcr.io/myorg/laravel-app:v1.0.0 \
--project my-project \
--port 8080 \
--healthcheck /up \
--cpu 500 \
--memory 512 \
--regions falkenstein-1 \
--env APP_ENV=production \
--env APP_DEBUG=false \
--secrets APP_KEY=laravel-app-key \
--secrets DB_PASSWORD=db-passwordSee Deploy an HTTP container with flags for the full flag reference and Deploy your first container for the Console walkthrough.
Databases and migrations
Bahriya does not host your database — connect Laravel to your own managed database using host, database, user, and password values supplied through secrets. Run php artisan migrate --force as a one-off before or after a deploy rather than inside the web process; the same image with a migrate command works well for this.
Next steps
- Deploy your first container — the end-to-end walkthrough.
- Environment variables — plain config versus secrets.
- Secrets — encrypted values injected at runtime.
- Persistent storage — storage that survives restarts.